【问题标题】:Capturing Value instead of Reference in Lambdas在 Lambda 中捕获值而不是引用
【发布时间】:2015-01-18 21:21:23
【问题描述】:

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 的引用。

这是正确的解释吗?

【问题讨论】:

标签: python python-2.7 lambda


【解决方案1】:

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

lst.append(lambda i=i: i)

【讨论】:

    【解决方案2】:

    看来这个工作的原因是当 i 被提供时 对于外部 lambda,外部 lambda 创建一个范围并取消引用 i,将 a 设置为 i。然后,返回的内部 lambda 包含一个 参考a。

    这是正确的解释吗?

    我不喜欢它。 Python 不通过引用传递:

    def func(x):
        x = 10
    
    num = 3
    func(num)
    
    print num  #=>3
    

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

    这个例子有效的原因是因为规则:

    函数的局部变量在执行完毕后被销毁。

    函数的局部变量包括其参数变量。每次执行外部 lambda 时,都会创建一个新的“a”变量。因此,每个内部 lambda 都会关闭不同的“a”变量。

    您确实提到了这种情况:

    外部 lambda 创建一个作用域

    ...

    lambda 正在捕获对 i 的引用,而不是 i 的值。

    或者,我喜欢这样说。

    闭包关闭变量而不是值。

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 是的!我对闭包的概念很熟悉!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-28
      • 2016-02-25
      • 2010-10-01
      相关资源
      最近更新 更多