说我有一些函数fun
,其实际代码体不受我的控制。我可以创建一个新函数,在调用fun
之前进行一些预处理,即
def process(x):
x += 1
return fun(x)
如果我现在希望process
取代fun
以便将来调用fun
,我需要做类似的事情
# Does not work
fun = process
然而,这不起作用,因为这会产生循环参考问题,因为现在fun
是从fun
体内调用的。我发现的一个解决方案是在fun
中引用process
的副本,如下所示:
# Works
import copy
fun_cp = copy.copy(fun)
def process(x):
x += 1
return fun_cp(x)
fun = process
但这个解决方案困扰我,因为我不知道Python如何构建函数的副本。我想我的问题与使用继承和super
函数扩展类方法的问题相同,但在这里我没有类。
我该怎么做呢?我认为这是一个足够普遍的任务,应该存在一些或多或少的惯用解决方案,但我找不到运气。
Python没有构建函数的副本。 copy.copy(fun)
刚刚返回fun
;区别在于你将它保存到fun_cp
变量,这是一个与你保存process
的变量不同的变量,所以当fun_cp
试图寻找它时它仍然在process
。
我会做类似于你所做的事情,将原始函数保存到另一个变量,只是没有“复制”:
original_fun = fun
def fun(x):
x += 1
return original_fun(x)
如果你想将相同的包装应用于多个函数,定义装饰器和执行fun = decorate(fun)
更具有可重用性,但对于一次性,它需要的工作量超过必要性和额外的缩进级别。
这看起来像python的闭包的用例。有一个功能返回你的功能。
def getprocess(f):
def process(x):
x += 1
return f(x) # f is referenced from the enclosing scope.
return process
myprocess = getprocess(fun)
myprocess = getprocess(myprocess)
感谢coldspeed使用闭包的想法。一个完全工作和抛光的解决方案是
import functools
def getprocess(f):
@functools.wraps(f)
def process(x):
x += 1
return f(x)
return process
fun = getprocess(fun)
请注意,这相当于将装饰器(getprocess
)应用于fun
。我无法想出这个解决方案,因为专用的装饰器语法@getprocess
只能在函数的定义位置使用(这里是fun
)。要将其应用于现有功能,请执行fun = getprocess(fun)
。