2009-12-17 51 views
7

鑑於這一代碼片段: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如何與範圍一起工作?

+2

常見問題,問(回答)至少一次前:http://stackoverflow.com/questions/233673/lexical-closures-in-python – 2009-12-17 20:16:58

+0

@Vladimir:Yeap,但兩者的頭銜完全不同,我永遠不會猜測他們是一樣的。 – OscarRyz 2009-12-17 20:25:43

回答

8

這是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當前值。

5

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'] 
4

你知道答案:是的。 ;)然而,安慰,因爲這是一個發芽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]