在 Lambdas 中捕获值而不是引用

Capturing Value instead of Reference in Lambdas

Eli Bendersky (http://eli.thegreenplace.net/2015/the-scope-of-index-variables-in-pythons-for-loops/)

给出的这个例子让我有点吃惊
>>> def foo():
...     lst = []
...     for i in range(4):
...         lst.append(lambda: i)
...     print([f() for f in lst])
...
>>> foo()
[3, 3, 3, 3]

但是当我考虑它时,它是有道理的 — lambda 正在捕获对 i 的引用而不是 i 的值。

所以解决这个问题的方法如下:

>>> def foo():
...     lst = []
...     for i in range(4):
...         lst.append((lambda a: lambda: a)(i))
...     print([f() for f in lst])
...
>>> foo()
[0, 1, 2, 3]

这似乎有效的原因是当 i 被提供给外部 lambda 时,外部 lambda 创建一个范围并取消引用 i,将 a 设置为 i。然后,返回的内部 lambda 包含对 a.

的引用

这个解释正确吗?

是的,看起来是正确的。如果您熟悉 javascript 并知道闭包,您会注意到它们有多么相似。

如果不是 - 有一个很好的 explanation on SO regarding JS closures 并且概念完全相同(以及解释,甚至错误和正确的用法)。

默认参数是获取值的另一种方式:

lst.append(lambda i=i: i)

It appears that the reason that this works is that when i is provided to the outer lambda, the outer lambda creates a scope and dereferences i, setting a to i. Then, the inner lambda, which is returned, holds a reference to a.

Is this a correct explanation?

我不喜欢。 Python 不通过引用:

def func(x):
    x = 10

num = 3
func(num)

print num  #=>3

因此,术语 reference 和 dereference 不在 python 词典中。或者,您可以说 python 总是 在将函数参数分配给参数变量之前取消引用函数参数——所以您的解释并没有真正解释任何东西。

示例之所以有效是因为规则:

A function's local variables are destroyed after it finishes executing.

函数的局部变量包括它的参数变量。每次执行外部 lambda 时,都会创建一个新的 'a' 变量。结果,每个内部 lambda 关闭不同的 'a' 变量。

你确实提到了那种情况:

the outer lambda creates a scope

...

the lambda is capturing a reference to i rather than i's value.

或者,正如我喜欢的说法。

A closure closes over variables--not values.

这就是大多数语言中闭包的工作方式(perl 是一个例外,闭包关闭值)。