python lambda与本地值的绑定

puruo6ea  于 2021-09-29  发布在  Java
关注(0)|答案(2)|浏览(356)

下面的代码显示 1 两次,但我希望看到 0 然后 1 .

def pv(v) :
  print v

x = []
for v in range(2):
  x.append(lambda : pv(v))

for xx in x:
  xx()

我希望python lambdas在幕后绑定到局部变量所指向的引用。然而,情况似乎并非如此。我在一个大型系统中遇到了这个问题,其中lambda正在执行现代c++的绑定(例如boost::bind),在这种情况下,您将绑定到智能ptr或复制为lambda构建一个副本。
那么,如何将局部变量绑定到lambda函数,并使其在使用时保留正确的引用呢?这种行为让我目瞪口呆,因为我不希望这种语言使用垃圾收集器。

cx6n0qe3

cx6n0qe31#

改变 x.append(lambda : pv(v))x.append(lambda v=v: pv(v)) .
您期望“python lambdas在幕后绑定到局部变量所指向的引用”,但python不是这样工作的。python在调用函数时查找变量名,而不是在创建函数时。使用默认参数是有效的,因为默认参数是在创建函数时计算的,而不是在调用函数时计算的。
这并不是lambdas的特别之处。考虑:

x = "before foo defined"
def foo():
    print x
x = "after foo was defined"
foo()

印刷品

after foo was defined
vkc1a9a2

vkc1a9a22#

lambda的闭包保存对正在使用的变量的引用,而不是它的值,因此如果变量的值以后发生更改,闭包中的值也会发生更改。也就是说,闭包变量的值是在调用函数时解析的,而不是在创建函数时解析的(python在这里的行为在函数式编程世界中并不罕见,这是值得的。)
有两种解决方案:
使用默认参数,在定义时将变量的当前值绑定到本地名称。 lambda v=v: pv(v) 使用双lambda并立即调用第一个lambda。 (lambda v: lambda: pv(v))(v)

相关问题