匿名函数在python中引用局部变量

ajw*_*ood 7 python variables scope callback

如何在python中定义匿名函数,其中bahaviour应该在definiton-time取决于局部变量的值,并且还接受参数

例:

def callback(val1, val2):
   print "{0} {1}".format(val1, val2)

i = 0
f0 = lambda x: callback(i, x)
i = 1
f1 = lambda x: callback(i, x)

f0(8) # prints "1, 8: but I'd like "0, 8" (value of 'i' when f0 was defined)
f1(8) # prints "1, 8"
Run Code Online (Sandbox Code Playgroud)

这样的事情可能没有将我的回调包装在自己的类中吗?

jdi*_*jdi 8

使用functools.partial在python中进行闭包

from functools import partial

i = 0
f0 = partial(callback, i)
i = 1
f1 = partial(callback, i)

f0()
# 0
f1()
# 1
Run Code Online (Sandbox Code Playgroud)

partial就像一个lambda,但在那一刻将值包含在arg中.当它被调用时不评估它.

仅包装一些args

是partial将允许您包装任意数量的参数,然后可以将剩余的args和kwargs传递给生成的部分对象,以便它像调用原始包装函数一样运行...

def callback(val1, val2):
   print "{0} {1}".format(val1, val2)

i = 0
x = 8
f0 = partial(callback, i)
f0(x)
# 0 8
Run Code Online (Sandbox Code Playgroud)

基本上你已经缠callback(val1, val2)callback(val2)val1被列为封闭了.

使用lambda的类似效果的示例

如果你真的想看看如何用lambda闭包来做这件事,你可以看到为什么它变得丑陋而偏爱是优选的......

f0 = (lambda val1: lambda val2: callback(val1, val2))(i)
Run Code Online (Sandbox Code Playgroud)

您必须将scope变量包装到外部函数作用域中,然后在内部lambda函数中引用该作用域.育.

来自异常的回溯:部分vs lambda vs嵌套函数

随着其他答案的涌入,我想我会概述使用partial而不是lambda或内部/外部函数闭包的另一个原因.请记住,我的意思是功能关闭.functools.partial修复了包装函数引发异常时将获得的回溯...

考虑这个版本将除以零:

def callback(val1, val2):
    return val1 / val2
Run Code Online (Sandbox Code Playgroud)

正常的外/内封闭

def wrapper(fn, val1):
    def wrapped(val2):
            return fn(val1, val2)
    return wrapped

f0 = wrapper(callback, i)
f0(0)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in wrapped
  File "<stdin>", line 2, in callback
ZeroDivisionError: integer division or modulo by zero
Run Code Online (Sandbox Code Playgroud)

lambda闭合

f0 = (lambda val1: lambda val2: callback(val1, val2))(i)
f0(0)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
  File "<stdin>", line 2, in callback
ZeroDivisionError: integer division or modulo by zero
Run Code Online (Sandbox Code Playgroud)

现在为functools.partial

f0 = partial(callback, i)
f0(0)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in callback
ZeroDivisionError: integer division or modulo by zero
Run Code Online (Sandbox Code Playgroud)