Python lambda 绑定到本地值

Posted

技术标签:

【中文标题】Python lambda 绑定到本地值【英文标题】:Python lambda's binding to local values 【发布时间】:2012-05-14 05:32:15 【问题描述】:

以下代码吐出两次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 函数并让它在使用时保留正确的引用?我对这种行为感到非常惊讶,因为我不希望有垃圾收集器的语言会出现这种情况。

【问题讨论】:

我见过这个问题的几个变种。有人需要汇总所有这些,将标题更改为令人难忘的内容,然后告诉互联网谷歌 啊,给你,几乎是重复的:lexical-closures-in-python @shep,是的,我无法正确表达它,我试图复制 lua 的工作方式。 Python 的奇怪之处在于循环变量在循环之后仍然存在,因此在循环内定义并引用循环变量的函数在循环外调用时不会抛出 NameError。在大多数其他语言中,循环变量只能在循环本身内访问。 【参考方案1】:

x.append(lambda : pv(v)) 更改为x.append(lambda v=v: pv(v))

您希望“python lambdas 在幕后绑定到局部变量指向的引用”,但这不是 Python 的工作方式。 Python 在调用函数时查找变量名,而不是在创建时查找。使用默认参数是可行的,因为默认参数是在创建函数时计算的,而不是在调用它时。

这并不是 lambda 的特殊之处。考虑:

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

打印

after foo was defined

【讨论】:

很有趣,请您详细说明一下机制的直觉。 一个更明显的替代方法是使用functools.partial 或使用单独的辅助函数来创建闭包(def make_closure(v): return lambda: pv(v),您可以将其放入test)。 所以我的真实代码应该像lambda par1, par2 = l3_e : self.parse_l4(par1, par2) ? 如果v 本身就是一个引用(而不是int),那么我认为它不会是一个“深层”副本? @AaronMcDaid 它不会。【参考方案2】:

lambda 的闭包持有对正在使用的变量的引用,而不是它的值,所以如果变量的值稍后发生变化,闭包中的值也会发生变化。也就是说,闭包变量的值是在调用函数时解析的,而不是在创建函数时解析的。 (Python 在这里的行为在函数式编程世界中并不少见,因为它的价值。)

有两种解决方案:

    使用默认参数,在定义时将变量的当前值绑定到本地名称。 lambda v=v: pv(v)

    使用双 lambda 并立即调用第一个。 (lambda v: lambda: pv(v))(v)

【讨论】:

我喜欢第二种方法,因为我想冻结在当前值的变量不一定是 lambda 的参数。 @g.a.该值不需要已经是第一个技术工作的 lambda 参数。相反,真的

以上是关于Python lambda 绑定到本地值的主要内容,如果未能解决你的问题,请参考以下文章

SWIG Python 绑定到本地代码不适用于 OpenCV 2.1

基于 XAML 绑定到区域性名称属性,使用不同区域性在 WPF GridView 中本地化货币值

将按钮绑定到VPython 7功能

一些 Python 对象未绑定到检查点值

python里 key=lambda d:d[0]是啥意思?谢谢

找不到使用 lambda 的数据绑定事件的方法