为什么这两个'x'指的是不同的变量?

时间:2012-09-12 05:38:36

标签: python

在此代码中,lambda中的x指的是for语句中的x。所以y[0]()会返回2:

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

但是在这段代码中,lambda中的x指的是全局x,所以x[0]()返回全局x本身:

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

我想知道为什么lambda中的x引用第一段代码中的局部x而第二段代码中的全局x。

3 个答案:

答案 0 :(得分: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']

答案 1 :(得分: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

答案 2 :(得分: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]