如何包装递归函数,包括递归调用?例如,给定foo
和wrap
:
def foo(x):
return foo(x - 1) if x > 0 else 1
def wrap(f):
def wrapped(*args, **kwargs):
print "f was called"
return f(*args, **kwargs)
return wrapped
wrap(foo)(x)
只会在第一次通话时输出"f was called"
。递归调用仍然会解决foo()
。
我不介意猴子修补,或在内部戳。我不打算将这个代码添加到下一个核弹头处理程序中,所以即使这是一个坏主意,我也希望达到这个效果。
修改:例如,是否会修补foo.func_globals
以覆盖foo.__name__
工作?如果它总是这样,我应该注意任何副作用吗?
答案 0 :(得分:10)
如果你使用你的包装函数作为装饰器,它就可以工作。
def wrap(f):
def wrapped(*args, **kwargs):
print "f was called"
return f(*args, **kwargs)
return wrapped
@wrap
def foo(x):
return foo(x - 1) if x > 0 else 1
原因在于,在您的示例中,您只调用wrap
函数的结果一次。如果你将它用作装饰器,它实际上用模块命名空间替换模块命名空间中foo
的定义,因此它的内部调用解析为包装版本。
答案 1 :(得分:0)
用类而不是函数包装函数:
>>> def foo(x):
... return foo(x-1) if x > 0 else 1
...
>>> class Wrap(object):
... def __init__(self, f): self.f = f
... def __call__(self, *args, **kwargs):
... print "f called"
... return self.f(*args, **kwargs)
...
>>> foo = Wrap(foo)
>>> foo(4)
f called
1