什么(lambda)函数闭包在Python中捕获?

问题:

最近我开始玩Python,我来到了一些独特的方式,关闭工作。请考虑以下代码:

adders=[0,1,2,3]

for i in [0,1,2,3]:
   adders[i]=lambda a: i+a

print adders[1](3)

它构建一个简单的函数数组,该函数采用单个输入并返回一个数字所添加的输入。函数在for循环中构造,其中迭代器i03。对于每个这些数字,创建一个捕获i并将其添加到函数的输入的lambda函数。最后一行使用3作为参数调用第二个lambda函数。令我惊讶的是,输出是6
我预计4。我的推理是:在Python中,一切都是一个对象,因此每个变量都是必须的指针。当为i创建lambda闭包时,我希望它存储一个指向i当前指向的整数对象的指针。这意味着当i分配一个新的整数对象时,它不应该影响以前创建的闭包。不幸的是,检查调试器中的adders数组表明它是这样的。所有lambda函数指的是i 3的最后一个值,adders[1](3)返回6
这让我想到以下几点:

  • 关闭捕获什么?
  • 说服lambda函数捕获i的当前值的最优雅的方式是什么,当i更改其值时不会受到影响?

回答:

你的第二个问题已经回答了,但是对于你的第一个问题:

关闭捕获是什么?

Python中的范围是dynamic and词法。闭包将始终记住变量的名称和范围,而不是其指向的对象。由于您的示例中的所有函数都在相同的范围内创建并使用相同的变量名称,所以它们总是引用相同的变量。
 编辑:关于你如何克服这个问题的其他问题,有两种方法可以想到:

  1. one recommended by Adrien Plisson最简洁而不是严格等同的方式。创建一个带有额外参数的lambda,并将额外的参数的默认值设置为要保留的对象。
  2. 每次创建lambda时,会创建一个新的范围:
     >>> adders = [0,1,2,3]
    >>>对于我在[0,1,2,3]中:
    ...加法器[i] =(lambda b:lambda a:b + a)(i)
    ...
    >>>加法器[1](3)
    4
    >>>加法器[2](3)


    这里的范围是使用一个新的函数(一个简短的lambda)创建的,该函数绑定其参数,并传递要绑定的值作为参数。在实际的代码中,尽管如此,你很可能会有一个普通的函数而不是lambda来创建新的范围:
    def createAdder(x):
        返回lambda y:y + x
    adders = [createAdder(i)for i in range(4)]

 
 
Code问答: http://codewenda.com/topics/python/
Stackoverflow: What do (lambda) function closures capture in Python?

*转载请注明本文链接以及stackoverflow的英文链接

发表评论

电子邮件地址不会被公开。 必填项已用*标注

92 − 87 =