如何在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"
如果没有将我的回调包装在自己的类中,这样的事情是否可能?
答案 0 :(得分:8)
from functools import partial
i = 0
f0 = partial(callback, i)
i = 1
f1 = partial(callback, i)
f0()
# 0
f1()
# 1
partial
就像一个lambda,但在那一刻将值包装到arg中。在调用时不评估它。
是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
基本上,您已将callback(val1, val2)
包裹到callback(val2)
中,val1
已被包含为关闭。
如果您真的想看看如何使用lambda闭包来实现这一点,您可以看到为什么它变得丑陋而且部分是首选......
f0 = (lambda val1: lambda val2: callback(val1, val2))(i)
您必须将scope变量包装到外部函数作用域中,然后在内部lambda函数中引用该作用域。育。
随着其他答案的涌入,我想我会概述使用partial而不是lambda或内/外函数闭包的另一个原因。请记住,我的意思是功能关闭。 functools.partial修复了当你的包装函数引发异常时你将得到的回溯......
考虑这个版本将除以零:
def callback(val1, val2):
return val1 / val2
正常的外部/内部关闭
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
lambda closure
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
现在为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
答案 1 :(得分:1)
你可以通过functools.partial来实现这个目标:
f0 = partial(callback, i)
答案 2 :(得分:0)
您可以创建一个创建功能的功能。如其他人所提到的,partial
是另一种选择。
def repeater(s):
def anon():
print s
return anon
greet = repeater("Hello, World")
greet()
答案 3 :(得分:0)
虽然在这种情况下使用functools.partial是更好的解决方案,但您也可以创建显式闭包:
def callback_generator(val):
def callback():
return val
return callback
i = 0
f0 = callback1(i)
i = 1
f1 = callback1(i)
这也可以用lambdas完成,如下面的评论所示。