在Lambda中捕获值而不是引用

时间:2015-01-18 21:21:23

标签: python python-2.7 lambda

我对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持有对。

的引用

这是正确的解释吗?

3 个答案:

答案 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,概念绝对相同(以及解释,甚至是错误和正确的用法)。