10

我想要一个 lambdas 列表,作为一些繁重计算的缓存,并注意到这一点:

>>> [j() for j in [lambda:i for i in range(10)]]
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]

虽然

>>> list([lambda:i for i in range(10)])
[<function <lambda> at 0xb6f9d1ec>, <function <lambda> at 0xb6f9d22c>, <function <lambda> at 0xb6f9d26c>, <function <lambda> at 0xb6f9d2ac>, <function <lambda> at 0xb6f9d2ec>, <function <lambda> at 0xb6f9d32c>, <function <lambda> at 0xb6f9d36c>, <function <lambda> at 0xb6f9d3ac>, <function <lambda> at 0xb6f9d3ec>, <function <lambda> at 0xb6f9d42c>]

这意味着 lambda 是独特的函数,但它们都以某种方式共享相同的索引值。

这是错误还是功能?我该如何避免这个问题?它不仅限于列表推导...

>>> funcs = []
... for i in range(10):
...     funcs.append(lambda:i)
... [j() for j in funcs]
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
4

5 回答 5

18

lambda返回i您调用它时的值。由于您lambda在循环完成运行后调用 ,因此 的值i将始终为 9。

您可以在 lambda 中创建一个局部i变量来保存定义时的值lambda

>>> [j() for j in [lambda i=i:i for i in range(10)]]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

另一种解决方案是创建一个返回的函数lambda

def create_lambda(i):
    return lambda:i
>>> [j() for j in [create_lambda(i) for i in range(10)]]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

这是有效的,因为i每次调用create_lambda.

于 2012-04-09T08:08:10.817 回答
11

你在这里看到的是闭包的效果。lambda 正在从程序中捕获状态以供以后使用。因此,虽然每个 lambda 都是唯一的对象,但状态不一定是唯一的。

这里实际的“gotchya”是变量i被捕获,而不是i在那个时间点表示的值。我们可以用一个更简单的例子来说明这一点:

>>> y = 3
>>> f = lambda: y
>>> f()
3
>>> y = 4
>>> f()
4

lambda 保留对变量的引用,并在您执行 lambda 时评估该变量。

要解决此问题,您可以分配给 lambda 中的局部变量:

>>> f = lambda y=y:y
>>> f()
4
>>> y = 6
>>> f()
4

最后,在循环的情况下,循环变量只“声明”一次。因此,在循环中对循环变量的任何引用都将持续到下一次迭代之后。这包括列表推导中的变量。

于 2012-04-09T08:07:38.397 回答
1

问题是您没有在列表理解的每次迭代中捕获 i 的值,而是每次都在捕获变量。

问题是闭包通过引用捕获变量。在这种情况下,您正在捕获一个其值随时间变化的变量(与所有循环变量一样),因此运行它时它的值与创建它时的值不同。

于 2012-04-09T08:08:50.500 回答
0

我不确定它是错误还是功能,但正在发生的事情是lambda:i在形成 lambda 函数之前没有评估 i 。因此,它实际上只是一个评估 i 的当前值的函数。这是如何发生的另一个示例。

>>> i=5
>>> x=lambda:i
>>> x()
5
>>> i=6
>>> x()
6

因此,显然,除了 i 在您的示例中将变为 9 之外,发生的事情是相同的,因为它是按该顺序通过 0 到 9 的范围分配的。

我认为没有什么好的方法可以避免它。Python 中的 Lambda 函数非常有限。它本质上并不是一种真正的函数式语言。

于 2012-04-09T08:06:53.937 回答
0

将方括号变成括号,如下所示: [j() for j in (lambda:i for i in range(10))] 输出: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 元组是不可变的变量

于 2020-09-25T06:32:33.507 回答