関数の引数について勉強している初学者です。
引数には位置引数、キーワード引数、デフォルト引数などがあると学びました。
そしてデフォルト引数値で以下のような2つのコードの違いを検討していたのですが、いまいち違いがわからないので質問します。
def test(arg, result=[]): result.append(arg) print(result) test('a') test('b') print(test('a'))
結果は以下です。
['a'] ['a', 'b']
後者のコードは以下です。
def test(arg): result = [] result.append(arg) print(result) test('a') test('b') print(test('a'))
結果は以下です。
['a'] ['b']
本来目的は後者の方のように、aとbという引数がそれぞれ一つずつリストに加えられた状態で出力される
というものでした。
前者のコードではtestを呼び出した際にaで呼びたした時はresultは空であるが、bで呼び出した時には前回呼び出した要素が残っているので、['a', 'b']と表示されると説明がありましたが、そこがいまいち理解できません。
自分の中では後者のコードではresultは関数内で定義されたローカル変数です。関数内というローカルなスコープで'a'を引数としてresultのリストに追加しても、それはローカル内の出来事なので、次のtest('b')には影響せず、結果のように別々に表示されると考えました。
前者の方はresultの方もデフォルト引数値として空のリスト[]を与えています。だから、test('a')の後にtest('b')をやっても結局デフォルトでresult=[]となっているから、test('b')を実行した際にはresult=[]がデフォルト引数値となるので、test('a')の影響は受けないと思うのですが、test('b')の結果は['a', 'b']となっています。
以上のことについての回答や、自分の考えの間違いの指摘を頂けたら幸いです。
mac 10.14.1
visual studio code
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
__defaults__と__kwdefaults__の使い方について、質問の返信スペースではわかりにくくなるため、ここに質問内容を記載します。
以下のようなコードを作成し、使い方について自分なりに考えてみました。
def func(args=[21]): print(args) func.__defaults__[0].append(42) func() #>>>[21, 42] def kinou(args=['mail', 'address']): print(args) kinou.__defaults__[0].remove('mail') kinou() #>>>['address'] def lite(args='slim'): print(args) lite() lite.__defaults__ = 'spam', lite() #>>>slim # spam
関数が呼び出された際不足している実引数を補う際に利用されるとのことだったので、色々な値を動かしてみました。
LouiS0616さんが提示してくれたコードは以下でした。
>>> def func(args=[]): ... print(args) ... >>> func() [] >>> >>> func.__defaults__[0].append(42) >>> func() [42] >>> >>> func.__defaults__ = 'spam', >>> func() spam
まず、自分が悩んだのは[0].append(42)の[0]でした。この[0]がどういった意味で置かれているのかがわからずまずは[]という空のリストにしてみるとエラーがでしまいました。
そして、たどり着いたのが自分の作ったコードのfunc関数でした。[21, 42]が結果としてでてくることから、[0]は42という実引数を入れるのに必要なもので、args=[21]を表しているのかなと思いました。しかし、[0]とするのが定義上の決まりなのかどうかがわかりませんでした。
つぎに、たどり着いたのが、kinou関数でした。appendできるならremoveもできるのかなと思い実行するとできました。やはり、[0]はargsのリストを表しているということが確信できました。
そして、func.defaults = 'spam',について考えました。おそらくargs=[]の=以降を変更するのではと考え、args='slim'として行ったところ、spamに変更されていたので、=とするとデフォルト値を変更できるのではという結論に自分の中で至りました。
また、'spam',の,が気になったので、'spam'と変更してみると、
TypeError: defaults must be set to a tuple object
と表示されました。一応公式では__defaults__は『デフォルト値を持つ引数に対するデフォルト値が収められたタプル』となっていたので、タプルでは('aaa',)というように,が必要だったのを思い出すと=でデフォルト値を変更する時はタプルとしての操作をする(先例のリストの追加をするときの[0]とは別)のかなと納得しましたが、そういう理解でいいのか確証はありません。
また、__kwdefaults__は公式によると、キーワード専用パラメータのデフォルト値を含む辞書となっていたので、以下のようなコードを書いて実験してみました。
def moji(a, *, b='ow'): print(a,b,sep='') moji('r') #>>>row moji.__kwdefaults__ ='ing' moji('r') #>>>TypeError: __kwdefaults__ must be set to a dict object
となってしまいました。やはり、__kwdefaults__辞書のようです。キーワード専用パラメータのデフォルト値は結果として変更できませんでした。
また、辞書のような形式で変更してみたらどうだろうと思い、先ほどのリストのように以下のようにコードを作りました。
moji.__kwdefaults__ {0}['b']='ing' moji('r') #>>>moji.__kwdefaults__ {None:None}['b']='ing' # ^
func.defaults[0].append(42)のような形式で、辞書を値のない辞書として、0のかわりにNoneを使用してみましたが、エラーでした。
ネットや本を調べても詳細が見つからないので、上記の[0]の意味について、=での変更のについて、__kwdefaults__の使い方についての主に3つについて教えていただけたら幸いです。よろしくお願いします。
回答3件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/02/13 11:19
2019/02/13 11:58 編集
2019/02/14 05:54
2019/02/14 06:47
2019/02/14 08:13
2019/02/14 09:51
2019/02/14 10:04 編集