Python 函数组合(最大递归深度错误,作用域?)
这个函数有什么问题呢?看起来像是作用域错误(虽然我以为通过把每个可调用的函数放在列表里,而不是直接使用它,已经修复了这个问题)。错误信息是达到最大递归深度(当调用comp(inv, dbl, inc)时)...
注意:问题是:为什么它会递归,而不是为什么会达到最大深度...
def comp(*funcs):
if len(funcs) in (0,1):
raise ValueError('need at least two functions to compose')
# get most inner function
composed = []
print("appending func 1")
composed.append(funcs[-1])
# pop last and reverse
funcs = funcs[:-1][::-1]
i = 1
for func in funcs:
i += 1
print("appending func %s" % i)
composed.append(lambda *args, **kwargs: func(composed[-1](*args,**kwargs)))
return composed[-1]
def inc(x):
print("inc called with %s" % x)
return x+1
def dbl(x):
print("dbl called with %s" % x)
return x*2
def inv(x):
print("inv called with %s" % x)
return x*(-1)
if __name__ == '__main__':
comp(inv,dbl,inc)(2)
错误追踪(如果有帮助的话):
appending func 1
appending func 2
appending func 3
Traceback (most recent call last):
File "comp.py", line 31, in <module>
comp(inv,dbl,inc)(2)
File "comp.py", line 17, in <lambda>
composed.append(lambda *args, **kwargs: func(composed[-1](*args,**kwargs)))
File "comp.py", line 17, in <lambda>
composed.append(lambda *args, **kwargs: func(composed[-1](*args,**kwargs)))
File "comp.py", line 17, in <lambda>
composed.append(lambda *args, **kwargs: func(composed[-1](*args,**kwargs)))
(...)
File "comp.py", line 17, in <lambda>
composed.append(lambda *args, **kwargs: func(composed[-1](*args,**kwargs)))
RuntimeError: maximum recursion depth exceeded while calling a Python object
2 个回答
1
我不太明白你为什么一开始要生成这么多函数。其实你的代码可以简化成一个简单的版本:
def compose(*funcs):
if len(funcs) in (0,1):
raise ValueError('need at least two functions to compose')
# accepting *args, **kwargs in a composed function doesn't quite work
# because you can only pass them to the first function.
def composed(arg):
for func in reversed(funcs):
arg = func(arg)
return arg
return composed
# what's with the lambdas? These are functions already ...
def inc(x):
print("inc called with %s" % x)
return x+1
def dbl(x):
print("dbl called with %s" % x)
return x*2
def inv(x):
print("inv called with %s" % x)
return -x
if __name__ == '__main__':
f = compose(inv,dbl,inc)
print f(2)
print f(3)
6
你创建的这个lambda函数会对composed
变量形成一个闭包:
composed.append(lambda *args, **kwargs: func(composed[-1](*args,**kwargs)))
这意味着当你创建这个lambda函数时,composed[-1]
并不会被计算,而是在你调用它的时候才会被计算。这样一来,composed[-1]
就会不断地自我调用,形成递归。
你可以通过使用一个辅助函数(它有自己的作用域)来解决这个问题,从而创建lambda函数:
def comp2(f1, f2):
return lambda *args, **kwargs: f1(f2(*args, **kwargs))
...
for func in funcs:
composed.append(comp2(func, composed[-1]))