鑑於這一代碼片段:Python的lambda表達式和範圍
funcs = []
for x in range(3):
funcs.append(lambda: x)
print [f() for f in funcs]
我希望它打印[0, 1, 2]
,而是它打印[2, 2, 2]
。有什麼基礎知識我錯過了lambdas如何與範圍一起工作?
鑑於這一代碼片段:Python的lambda表達式和範圍
funcs = []
for x in range(3):
funcs.append(lambda: x)
print [f() for f in funcs]
我希望它打印[0, 1, 2]
,而是它打印[2, 2, 2]
。有什麼基礎知識我錯過了lambdas如何與範圍一起工作?
這是Python中的常見問題。基本上,該範圍是這樣的,即當調用f()
時,它將使用當前值x
,而不是在形成lambda時的值x
。有一個標準的解決方法:
funcs = []
for x in range(10):
funcs.append(lambda x=x: x)
print [f() for f in funcs]
採用lambda x = x
檢索和保存的x
當前值。
x被綁定到模塊級x(它從for循環中遺留下來)。
略知一二:
funcs = []
for x in range(10):
funcs.append(lambda: x)
x = 'Foo'
print [f() for f in funcs]
# Prints ['Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo']
你知道答案:是的。 ;)然而,安慰,因爲這是一個發芽pythonistas非常普遍的發現。當你定義一個函數或lambda引用該函數內的「未創建」的變量時,它會在變量上創建一個閉包。其效果是您在調用函數時獲取變量的值,而不是定義時的值。 (你期待後者。)
有幾種方法可以解決這個問題。首先是有約束力的額外變量:
funcs = []
for x in range(10):
funcs.append(lambda x=x: x)
print [f() for f in funcs]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
第二種方法是多了幾分正式:
from functools import partial
funcs = []
for x in range(10):
funcs.append(partial(lambda x: x, x))
print [f() for f in funcs]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
常見問題,問(回答)至少一次前:http://stackoverflow.com/questions/233673/lexical-closures-in-python – 2009-12-17 20:16:58
@Vladimir:Yeap,但兩者的頭銜完全不同,我永遠不會猜測他們是一樣的。 – OscarRyz 2009-12-17 20:25:43