5

重複の可能性:
Python ラムダとスコープ

私は、以下が値0、1、および2を取る3つの定数関数のリストを生成することを望んでいます:

lis = []
for i in range(3):
    lis.append( lambda: i )

しかし、それらはすべて値2を取ることになります。ディープコピーで問題を解決できると思いますが、うまくいかないようです。

4

2 に答える 2

1

次のような記述を避けるためにループします。

lis.append( lambda: 0 )
lis.append( lambda: 1 )
lis.append( lambda: 2 )

あなたの意図は、定数整数を返すラムダ関数を書くことです。しかし、 object を返す関数を定義して追加していますi。したがって、3 つの追加機能は同じです。

作成された関数の背後にあるバイト コードは次を返しますi

In [22]: import dis
In [25]: dis.dis(lis[0])
  3           0 LOAD_GLOBAL              0 (i)
              3 RETURN_VALUE        

In [26]: dis.dis(lis[1])
  3           0 LOAD_GLOBAL              0 (i)
              3 RETURN_VALUE        

In [27]: dis.dis(lis[2])
  3           0 LOAD_GLOBAL              0 (i)
              3 RETURN_VALUE   

これらの関数のいずれかを呼び出すと、サンプル コードにある最新の値が返されiます。2

In [28]: lis[0]()
Out[28]: 2

オブジェクトを削除するiと、エラーが発生します。

In [29]: del i

In [30]: lis[0]()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-30-c9e334d64652> in <module>()
----> 1 lis[0]()

<ipython-input-18-15df6d11323a> in <lambda>()
      1 lis = []
      2 for i in range(3):
----> 3     lis.append( lambda: i )

NameError: global name 'i' is not defined

解決策は、ループを使用して必要な定数でコードを記述し、実際にそのコードを実行することです。

In [31]: lis = []
    ...: for i in range(3):
    ...:     exec 'lis.append( lambda: {} )'.format(i)
    ...:  

次の結果が得られます。

In [44]: lis[0]()
Out[44]: 0

In [45]: lis[1]()
Out[45]: 1

In [46]: dis.dis(lis[0])
  1           0 LOAD_CONST               1 (0)
              3 RETURN_VALUE        

In [47]: dis.dis(lis[1])
  1           0 LOAD_CONST               1 (1)
              3 RETURN_VALUE        
于 2012-12-26T01:22:39.083 に答える