私はこの簡単なコードを書きました:
def makelist():
L = []
for i in range(5):
L.append(lambda x: i**x)
return L
わかりました、今私は電話します
mylist = makelist()
ネストされた関数が後で呼び出されたときに囲んでいるスコープ変数が検索されるため、それらはすべて事実上同じ値を記憶します。このため、最後のループ反復でループ変数が持っていた値を見つけることを期待していましたが、リストを確認するとそうですか:
>>> mylist[0](0)
1
>>> mylist[0](1)
4
>>> mylist[0](2)
16
>>>
私はとても混乱しています、なぜ私のコードは最後のforループ値を保持しないのですか?次のようなデフォルトの引数を使用して、囲んでいるスコープ値を明示的に保持する必要がないのはなぜですか。
L.append(lambda x, i=i: i ** x)
前もって感謝します
にもかかわらずi
効果的に1つのだけで、時間をかけて複数の値をとる変数は、i
。の内容はi
ループ中に変更されています。ただし、クロージャは値ではなく変数をキャプチャします。ラムダを呼び出すまで、ラムダ内では何も評価されません。関数を呼び出すときに、現在の値にアクセスしますi
。これはたまたま最後の値です。
なぜi=i
問題が解決するのかについては、これは、たとえば、ヒッチハイカーのPythonガイド(Common Gotchas)で説明されています。
Pythonのデフォルトの引数は、関数が呼び出されるたびにではなく、関数が定義されたときに1回評価されます(たとえば、Rubyのように)。つまり、変更可能なデフォルト引数を使用して変更すると、関数への今後のすべての呼び出しでもそのオブジェクトが変更されます。
したがって、作成したクロージャーの内部で発生する(そしてi
、外部のバインディングと同じように名前が付けられる)新しいバインディングには、クロージャーの作成時にデフォルト値が計算されます。その結果、「正しい」値が設定され、クロージャが呼び出されたときにすぐに使用できるようになります。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加