3

在这段代码中,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。

4

3 回答 3

6

我猜你在 python 2.x 上,在列表理解中,临时变量“泄漏”到命名空间中。您可以在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']
于 2012-09-12T05:42:01.120 回答
5

x指的是x两段代码中的全局。事实上,在这两段代码中都只有一个全局变量。x这里没有局部变量,只有全局变量。

在第一个示例中, 的全局值为x2,因为这是列表推导分配给它的最后一个值。列表推导式将它们的变量泄漏到@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
于 2012-09-12T05:58:28.413 回答
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]
于 2012-09-12T05:42:50.733 回答