Python lambda绑定到本地值

Has*_*yed 59 python lambda closures

以下代码吐出1两次,我期望看到0然后1

def pv(v) :
  print v


def test() :
  value = []
  value.append(0)
  value.append(1)
  x=[]
  for v in value :
    x.append(lambda : pv(v))
  return x

x = test()
for xx in x:
  xx()
Run Code Online (Sandbox Code Playgroud)

我希望python lambdas绑定到一个局部变量指向的引用,在场景后面.然而,情况似乎并非如此.我已经在一个大型系统中遇到了这个问题,其中lambda正在做现代C++的一个绑定的等价物(例如'boost :: bind'),在这种情况下,你将绑定到智能ptr或复制contstruct lambda的副本.

那么,如何将局部变量绑定到lambda函数并在使用时保留正确的引用?我对这种行为非常惊讶,因为我不希望这种语言来自垃圾收集器.

有问题的代码如下所示(l3_e是导致问题的变量):

 for category in cat :
      for l2 in cat[category].entries :
        for l3 in cat[category].entries[l2].entry["sub_entries"] :
          l3_e = cat[category].entries[l2].entry["sub_entries"][l3]
          url = "http://forums.heroesofnewerth.com/" + l3_e.entry["url"]
          self.l4_processing_status[l3_e] = 0
          l3_discovery_requests.append( Request(
            url, callback = lambda response : self.parse_l4(response,l3_e)))
          print l3_e.entry["url"]
    return l3_discovery_requests
Run Code Online (Sandbox Code Playgroud)

Ste*_*ski 90

更改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()
Run Code Online (Sandbox Code Playgroud)

版画

after foo was defined
Run Code Online (Sandbox Code Playgroud)

  • 一个更明显的选择是使用`functools.partial`或使用单独的辅助函数来创建闭包(`def make_closure(v):return lambda:pv(v)`,你可以将它放入`test`). (2认同)

kin*_*all 19

lambda的闭包包含对正在使用的变量的引用,而不是其值,因此如果变量的值稍后更改,则闭包中的值也会更改.也就是说,闭包变量的值在调用函数时解析,而不是在创建函数时解析.(Python在这里的行为在函数式编程世界中并不罕见,因为它的价值.)

有两种解决方案:

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

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