2010-12-13 105 views
5

生成的函數列表我有一個生成的匿名函數列表以下Python代碼:在python

basis = [ (lambda x: n*x) for n in [0, 1, 2] ]  
print basis[0](1) 

我本來期望它等同於

basis = [ (lambda x: 0*x), (lambda x: 1*x), (lambda x: 2*x) ] 
print basis[0](1) 

然而,儘管第二個片段打印出0,這是我所期望的,第一個打印2.第一個代碼片段有什麼問題,爲什麼它不像預期的那樣?

+0

相關的問題:http://stackoverflow.com/q/139819/4279 – jfs 2010-12-13 07:03:39

回答

8

你可以使用默認的參數對N新建一個封閉

>>> basis = [ (lambda x,n=n: n*x) for n in [0, 1, 2] ]  
>>> print basis[0](1) 
0 
+3

這種技術通常用於將方法作爲回調函數傳遞。它看起來像'register_event_handler(事件= EVT,回調=拉姆達cbVar1,cbVar2,S =自:s.handle_evt(cbVar1,cbVar2))'。 – 2010-12-13 05:22:35

2

的問題是,在第一個例子中,每個拉姆達被綁定到相同的n - 換句話說,它被捕獲變量,而不是變量的值。由於n具有2在循環結束時的值,每個拉姆達使用值2 n

顯然,你可以使用默認參數來解決這個問題:

basis = [ (lambda x,n=n: n*x) for n in [0, 1, 2] ] 
print basis[0](1) 

由於默認參數值是常數,對n=n右側的n將評估每一次循環,給你一個新的獲得的價值。

+0

有關如何解決這個問題的任何建議? – dzhelil 2010-12-13 05:11:15

+1

celil:我編輯了我的答案,提供了一個建議的修補程序,但它不是很優雅。 – Gabe 2010-12-13 05:16:48

+0

默認參數可能不是優雅,但他們輕鬆了許多赫克看比顯式部分的評價就像我以前做的:'基礎= [(拉姆達N:(拉姆達X:N * X))(N )爲範圍(3)中的n]'。 :/默認參數是不是在保持不變的意義上的「常數」,但它得到的評價,並綁定到拉姆達的'.func_defaults'。閉合參數也是如此,但顯然是以更神奇的方式... – 2010-12-13 07:56:19

3

因爲它的「按名稱傳遞」。

也就是說,在運行lambda時,執行n*xx勢必1(它是一個參數),n正在擡頭的環境(這是現在)。所以,結果是2

+0

這並不能解釋爲什麼當我們使用一個生成器理解而不是「泄漏」''n'到'locals()'中時,會出現同樣的行爲。 AFAICT,''n'的值是從lambda的'.func_closure'中查找的,而且這個神奇地指的是當'n'不再存在時,最後提到的任何'n'是如何神奇地指向的。 – 2010-12-13 07:32:44

0

我想幫助與卡爾Knechtel(12月13日'10在7註釋的理解:32)。下面的代碼演示瞭如何使用發電機,原拉姆達的定義給出了預期的結果,但它並沒有使用列表或元組:

>>> #GENERATOR 
... basis = ((lambda x: n*x) for n in [0, 1, 2]) 
>>> print(type(basis)) 
<type 'generator'> 
>>> basis = ((lambda x: n*x) for n in [0, 1, 2]) 
>>> print([x(3) for x in basis]) 
[0, 3, 6] 
>>> #TUPLE 
... basis = tuple((lambda x: n*x) for n in [0, 1, 2]) 
>>> print(type(basis)) 
<type 'tuple'> 
>>> print([x(3) for x in basis]) 
[6, 6, 6] 
>>> #LIST 
... basis = list((lambda x: n*x) for n in [0, 1, 2]) 
>>> print(type(basis)) 
<type 'list'> 
>>> print([x(3) for x in basis]) 
[6, 6, 6] 
>>> #CORRECTED LIST 
... basis = list((lambda x, n=n: n*x) for n in [0, 1, 2]) 
>>> print(type(basis)) 
<type 'list'> 
>>> print([x(3) for x in basis]) 
[0, 3, 6]