Possible Duplicate:
Python lambdas and scoping在Python中定義的函數列表
我希望下將產生的取值0,1和2 3個常數函數的列表:
lis = []
for i in range(3):
lis.append(lambda: i)
但他們都最終以價值2.我期望通過深拷貝來解決這個問題,但它似乎不起作用。
Possible Duplicate:
Python lambdas and scoping在Python中定義的函數列表
我希望下將產生的取值0,1和2 3個常數函數的列表:
lis = []
for i in range(3):
lis.append(lambda: i)
但他們都最終以價值2.我期望通過深拷貝來解決這個問題,但它似乎不起作用。
您環路避免編寫這樣的事:
lis.append(lambda: 0)
lis.append(lambda: 1)
lis.append(lambda: 2)
你的目的是要編寫返回常量整數lambda函數。但是你正在定義和追加一個返回對象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
診斷是正確的(這是一個關閉問題),但請不要使用'exec'!太可怕了!邪惡!討厭!不愉快! –
@ChrisMorgan我這裏唯一的目標是嘗試解釋lambda關閉的另一種方式,因爲它一次又一次地回來......這裏的'exec'是爲了說明期望的源代碼(OP的意圖)的元層次。我同意在@BasicWolf中使用lambda默認參數是解釋之外的方法。 – Boud
@ChrisMorgan這裏唯一的工作解決方案使用exec。你有更好的建議嗎? – kilojoules
@ Boud給出了一個非常好的答案,解釋了爲什麼你的代碼不能像你期望的那樣工作。虔誠地說,你必須在lambda中引用它之前評估i
的值。這樣做有點怪異:
lis = []
for i in range(3):
lis.append(lambda i=i: i)
這使用Python的默認函數參數的值功能,例如,在一個功能的一個會寫:現在
def f(i=10):
return i
,訣竅是一個參數具有存儲在該點它的默認值創建函數(的方法,lambda表達式)時。因此:
j = 10
def f(i=j):
return i
j = 20
print(f(125)) # no matter that j has been changed, the output is...
>>> 125
而同樣的技巧適用於lambda。爲了使它更清晰:
lis = []
for j in range(3):
lis.append(lambda i=j: i)
# Calling the lambdas
print(lis[1]())
>>> 1
事實上,使用默認參數是最常見的解決方案我見過。 –
這是一個標準的問題。例如http://stackoverflow.com/questions/1107210/python-lambda-problems,http://stackoverflow.com/questions/1924214/python-lambdas-and-scoping。許多,*許多*更多。 –
相關:[爲什麼map()和list的理解結果不一樣?](http://stackoverflow.com/questions/139819/why-results-of-map-and-list-comprehension-are-different) – jfs