2011-05-20 124 views
70

爲什麼以下兩個列表解析的輸出不同,即使f和lambda函數是相同的?Python:列表解析中的Lambda函數

f = lambda x: x*x 
[f(x) for x in range(10)] 

[lambda x: x*x for x in range(10)] 

你要知道,這兩種類型(f)和式(拉姆達X:X * X)返還相同種類。

+0

'[拉姆達X:X * X爲在範圍X(10)]'快於第一個,因爲它沒有調用外部循環函數,f代表eatedly。 – riza 2011-05-20 18:50:47

+0

@Selinap:...不,相反,您要通過循環創建一個品牌嶄新的功能。 ...和創建這個新功能的開銷,然後調用速度稍慢(無論如何我的系統上)。 – Gerrat 2011-05-20 19:00:12

+0

@Gerrat:即使有開銷,它仍然更快。但是,當然'[x * x在範圍內(10)]'更好。 – riza 2011-05-20 19:13:23

回答

142

第一個創建一個lambda函數並調用它十次。

第二個不調用該函數。它創建10個不同的lambda函數。它將所有這些列入清單。爲了讓相當於你所需要的第一:

[(lambda x: x*x)(x) for x in range(10)] 

或者更好的是:

[x*x for x in range(10)] 
+5

或'地圖(lambda x:x * x,範圍(10))',這可能是OP的意思首先。 – 2011-05-20 18:53:16

+0

是的,lambda x:x * x ..(x)似乎是信條。 – staticor 2013-08-19 16:09:48

+0

[lambda x:x * x在範圍內(10)] 基本上是haskell中的函數 – 2015-08-29 19:51:42

17

的最大區別在於,第一個例子中實際調用拉姆達f(x),而第二個例子沒有。

您的第一個示例相當於[(lambda x: x*x)(x) for x in range(10)],而第二個示例相當於[f for x in range(10)]

7

第一個

f = lambda x: x*x 
[f(x) for x in range(10)] 

運行f()那麼它f(x)爲每個值

第二個

[lambda x: x*x for x in range(10)] 

在範圍內的每個值會運行中的每個值拉姆達該列表,因此它會生成所有這些功能。

2

人民給了很好的答案,但忘了提,我認爲最重要的部分: 在第二個例子中,列表理解的X是不一樣的lambda功能的X,他們是完全無關的。 因此,第二個實施例實際上是相同的:

[Lambda X: X*X for I in range(10)] 

range(10)內部迭代僅用於在列表生成器10個類似lambda函數(10個獨立的功能,但完全類似負責 - 返回每個輸入的功率2 )。

。另一方面,第一個例子中的作品完全不同,因爲重複的X做的結果進行交互,每個迭代的值是X*X這樣的結果將是[0,1,4,9,16,25, 36, 49, 64 ,81]

+0

這是一個重要的觀點。我在你的答案中提出了你的建議並詳細闡述了它。 – 2015-12-01 13:19:19

36

這個問題倒是很「着名」和「顯而易見的」Python語法的一部分發臭 - 優先,lambda或列表理解。

我不認爲OP的目的是生成一個從0到9的方塊列表。如果是這樣的話,我們可以給更多的解決方案:

squares = [] 
for x in range(10): squares.append(x*x) 
  • 這是強制性語法的好醇」的方式。

但是這不是問題的關鍵。關鍵是W(hy)TF是否是這種模棱兩可的表達方式,所以反直覺?最後我對你有一個愚蠢的例子,所以不要太早拒絕我的回答(我在面試時曾經這樣做過)。

因此,OP的理解返回lambda表達式的列表:

[(lambda x: x*x) for x in range(10)] 

這當然只是10個不同平方函數的副本,請參閱:

>>> [lambda x: x*x for _ in range(3)] 
[<function <lambda> at 0x00000000023AD438>, <function <lambda> at 0x00000000023AD4A8>, <function <lambda> at 0x00000000023AD3C8>] 

注意的lambda的內存地址 - 它們都是不同的!

你當然可以有更多的 「最佳」(哈哈)版本的表情:

>>> [lambda x: x*x] * 3 
[<function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>] 

看到了嗎? 3次相同 lambda。

請注意,我用_作爲for變量。它與lambda中的x無關(它在詞法上被掩蓋了!)。得到它?

我要離開了討論,爲什麼語法優先不是這樣,它所有的意思是:

[lambda x: (x*x for x in range(10))] 

這可能是:[[0, 1, 4, ..., 81]],或[(0, 1, 4, ..., 81)],或這是我覺得最合乎邏輯的,這將是1個元素的list - 一個generator返回值。情況並非如此,這種語言不適用於這種方式。

什麼,如果...

,如果你不掩蓋for變量,並在你的lambda的使用它什麼???

好吧,那麼廢話發生。看看這個:

[lambda x: x * i for i in range(4)] 

這意味着課程:

[(lambda x: x * i) for i in range(4)] 

不過,這並不意味着:

[(lambda x: x * 0), (lambda x: x * 1), ... (lambda x: x * 3)] 

這僅僅是瘋了!

列表理解的lambda表達式是在這個理解的範圍封閉。一個詞彙封閉,所以他們通過參考參考i,而不是它的價值,當他們被評價過!

所以,這個表達式:

[(lambda x: x * i) for i in range(4)] 

大致等同於:

[(lambda x: x * 3), (lambda x: x * 3), ... (lambda x: x * 3)] 

我敢肯定,我們可以看到更多的在這裏使用一個Python反編譯器(我指的是例如在dis模塊),但對於Python-VM不可知的討論,這已經足夠了。 這麼多的求職面試問題。

現在,如何製作乘法器lambda的list,它真的乘以連續的整數?那麼,同樣接受的答案,我們需要通過包裝它在另一個lambda,這是越來越稱爲列表解析表達式打破直接領帶i

前:

>>> a = [(lambda x: x * i) for i in (1, 2)] 
>>> a[1](1) 
2 
>>> a[0](1) 
2 

後:

>>> a = [(lambda y: (lambda x: y * x))(i) for i in (1, 2)] 
>>> a[1](1) 
2 
>>> a[0](1) 
1 

(我不得不外的λ可變也= i,但我決定,這是更清晰的溶液 - 我介紹y,這樣我們都可以看到哪個女巫是哪個)。

+3

這是一個殘酷而不尋常的求職面試問題。 – szeitlin 2015-12-11 17:49:37

+1

我的頭燒焦閱讀你的答案! – Valilutzik 2016-09-25 17:57:51

+0

如果我的同事沒有問,我可能永遠不會搜索這個答案 – piggybox 2016-11-10 01:33:43

2

其他的答案是正確的,但如果你試圖使功能列表,每一個不同的參數,可以執行,下面的代碼將做到這一點:

import functools 
a = [functools.partial(lambda x: x*x, x) for x in range(10)] 

b = [] 
for i in a: 
    b.append(i()) 

In [26]: b 
Out[26]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 

雖然例子是人爲的,我認爲它是有用的時候想的功能的列表,每個打印不同的東西,即

import functools 
a = [functools.partial(lambda x: print(x), x) for x in range(10)] 

for i in a: 
    i()