2012-09-12 105 views
3

在此代碼中,lambda中的x引用for語句中的x。所以y[0]()回報2:爲什麼這兩個'x'指的是不同的變量?

x = 0 
y = [lambda : x for x in range(3)] 
y[0]() 

但在這個代碼,在拉姆達的X指的是全局X,所以x[0]()回報全局x本身:

x = [lambda : x for x in range(3)] 
x[0]() 

我想知道爲什麼X中lambda表示第一段代碼中的本地x,而第二段代碼中則表示全局x。

+0

因爲範圍......看到:HTTP://www.saltycrane.com/blog/2008/01/python-variable-scope-notes –

回答

5

x是指在兩個碼片全球x。的確,什麼都沒有,但在這兩個代碼段中都是全局的x。這裏沒有局部變量,只有全局變量。

在第一個示例中,x的全局值爲2,因爲這是列表理解分配給它的最後一個值。列表解析將它們的變量泄露到@wim所描述的封閉範圍中。由於這裏的封閉範圍是全局範圍,所以變量x泄漏到全局範圍中,覆蓋您之前設置的值0。

在第二個示例中,您將創建列表理解,然後將其值分配給(全局)變量x。這會覆蓋x中已有的內容,因此全局變量x的值現在成爲列表。

在這兩種情況下,當您調用列表中的某個函數(任何一個!)時,它將返回當前的值x。你可以在這裏看到:

>>> y = [lambda : x for x in range(3)] 
>>> y[0]() 
2 
>>> x = 88 
>>> y[0]() 
88 
>>> x = [lambda : x for x in range(3)] 
>>> y = x 
>>> y[0]() 
[<function <lambda> at 0x017789B0>, 
<function <lambda> at 0x01828DB0>, 
<function <lambda> at 0x01828F30>] 
>>> x = 88 
>>> y[0]() 
88 
6

我想你是在Python 2.x中,在列表理解中,臨時變量'泄漏'到命名空間中。你可以閱讀關於爲什麼在this blog post from Guido

在Python 2,列表解析「泄漏」循環控制變量 到周圍的範圍。這是原始 執行列表解析的假象;這是多年來Python的「骯髒的 小祕密」之一。

這已被固定在Python 3

我不知道爲什麼你是混亂的東西與lambda,在這裏你會看到在這個簡單的情況相同的行爲:

>>> x = 'a' 
>>> y = [x for x in 'b','c'] 
>>> x 
'c' 
>>> x = [x for x in 'b','c'] 
>>> x 
['b', 'c'] 
+0

個人而言,我更喜歡「泄露'的實現,因爲它在功能上與for循環相同,一旦完成,它也將其控制變量保留在範圍中。 –

+0

意見不同我猜想..我不喜歡它,可以想到沒有有效的'泄漏'用例,我確實被它蜇了一次。我認爲這種行爲被刪除是正確的,因爲我認爲列表理解是一個邏輯單元,控制只是一個自由變量而不是定義,與謂詞演算類似。 – wim

+0

是的,我當然明白並理解爲什麼。 –

2
>>> x='a' 
>>>x = [lambda : x for x in range(3)] 

只要迭代開始,x被分配到0,從range()返回(並且引用'a'被移除)。在最後一次迭代中,x的值變爲2,並且一旦LC退出,LC就被分配到x,所以現在x指向LC。

例如:

>>> [x for x in range(3)] 
[0, 1, 2] 
>>> x  
2 
>>> x=[x for x in range(3)] 
>>> x 
[0, 1, 2] 
相關問題