5

このコードが「a、b、c、d」ではなく「d、d、d、d」と出力するのはなぜですか? 「a、b、c、d」を出力するように変更するにはどうすればよいですか?

cons = []
for i in ['a', 'b', 'c', 'd']: 
    cons.append(lambda: i)  
print ', '.join([fn() for fn in cons])      
4

4 に答える 4

6

奇妙なことに、これは変数のスコープの問題ではなく、python のforループ (および python の変数) のセマンティクスの問題です。

ご想像のとおり、ラムダ内では、最も近い外側のスコープ内iの変数が正しく参照されます。iここまでは順調ですね。

ただし、これは次のことが起こることを意味すると予想しています。

for each value in the list ['a', 'b', 'c', 'd']: 
    instantiate a new variable, i, pointing to the current list member
    instantiate a new anonymous function, which returns i
    append this function to cons

実際に何が起こるかは次のとおりです。

instantiate a new variable i
for each value in the list ['a', 'b', 'c', 'd']: 
    make i refer to the current list member
    instantiate a new anonymous function, which returns i
    append this function to cons

したがって、コードは同じ変数iをリストに 4 回追加しています。ループが終了するまでiに、値は'd'.

Python 関数が引数の値を取得して値で返した場合、 の内容がへのi呼び出しごとにappend(または、さらに言えば、無名関数からの戻りごとに) コピーされるため、これに気付かないことに注意してください。で作成lambda)。ただし、実際には、python 変数は常に特定のオブジェクトへの参照iであるため、すべての 4 つのコピーが'd'ループの終わりまでに参照されます。

于 2013-02-06T21:18:06.397 に答える
2

クロージャを作成すると、ラムダ (この場合は ) によって「閉じられた」変数は、i値ではなく名前でバインドされます。したがって、ラムダを呼び出すたびに、「i」の最後の値が使用されます。

于 2013-02-06T21:18:48.520 に答える
2

これを機能させるために必要な簡単な修正は次のとおりです。

cons = []
for i in ['a', 'b', 'c', 'd']: 
    cons.append(lambda i=i: i)  
print ', '.join([fn() for fn in cons])     
于 2013-02-06T22:31:38.343 に答える
0

理解としての「エリック」の答え:

 cons =[lambda i= i:i for i in ['a', 'b', 'c', 'd']]   
 print ', '.join([fn() for fn in cons])     
于 2013-02-06T23:53:13.093 に答える