我对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的引用,而不是我的价值。
所以解决这个问题的方法如下:
>>> 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]
看起来这样做的原因是当我被提供给外部lambda时,外部lambda创建一个范围并解除引用i,将a设置为i。然后,返回的内部lambda持有对。
的引用这是正确的解释吗?
答案 0 :(得分:8)
默认参数是捕获值的另一种方法:
lst.append(lambda i=i: i)
答案 1 :(得分:2)
看来,这是有效的原因是当我被提供时 对于外部lambda,外部lambda创建范围和解引用 我,设置为i。然后,返回的内部lambda保持一个 参考a。
这是正确的解释吗?
我不喜欢它。 Python不通过引用传递:
def func(x):
x = 10
num = 3
func(num)
print num #=>3
因此,术语 referenc e和 dereference 不在python词典中。或者,您可以说python 始终在将参数变量分配给参数变量之前取消引用它 - 所以您的解释并没有真正解释任何内容。
该示例有效的原因是因为规则:
函数的局部变量在完成执行后会被销毁。
函数的局部变量包括其参数变量。每次外部lambda执行时,都会创建一个新的“a”变量。结果,每个内部lambda关闭一个不同的'a'变量。
你确实提到了这种状况:
外部lambda创建一个范围
...
lambda正在捕获对i的引用而不是i的值。
或者,我喜欢用它来表达。
闭包关闭变量 - 而不是值。
这就是闭包在大多数语言中的工作方式(perl是一个例外,其中闭包关闭了值)。
答案 2 :(得分:0)
是的,它看起来是正确的。如果你熟悉javascript并知道闭包,你会发现它们有多么相似。
如果没有 - 有一个很好的explanation on SO regarding JS closures,概念绝对相同(以及解释,甚至是错误和正确的用法)。