假设我有一个 Python 函数f
和fhelp
. fhelp
被设计为递归调用自身。f
不应该递归调用。有没有办法f
确定它是否被递归调用?
问问题
5544 次
2 回答
16
为此使用回溯模块:
>>> import traceback
>>> def f(depth=0):
... print depth, traceback.print_stack()
... if depth < 2:
... f(depth + 1)
...
>>> f()
0 File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f
None
1 File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in f
File "<stdin>", line 2, in f
None
2 File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in f
File "<stdin>", line 4, in f
File "<stdin>", line 2, in f
None
因此,如果堆栈中的任何条目表明代码是从 调用的f
,则该调用是(内)直接递归的。该traceback.extract_stack
方法使您可以轻松访问这些数据。下面if len(l[2] ...
示例中的语句仅计算函数名称的完全匹配数。为了让它更漂亮(感谢 agf 的想法),你可以把它变成一个装饰器:
>>> def norecurse(f):
... def func(*args, **kwargs):
... if len([l[2] for l in traceback.extract_stack() if l[2] == f.func_name]) > 0:
... raise Exception, 'Recursed'
... return f(*args, **kwargs)
... return func
...
>>> @norecurse
... def foo(depth=0):
... print depth
... foo(depth + 1)
...
>>> foo()
0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in func
File "<stdin>", line 4, in foo
File "<stdin>", line 5, in func
Exception: Recursed
于 2011-10-26T08:35:26.443 回答
3
您可以使用装饰器设置的标志:
def norecurse(func):
func.called = False
def f(*args, **kwargs):
if func.called:
print "Recursion!"
# func.called = False # if you are going to continue execution
raise Exception
func.called = True
result = func(*args, **kwargs)
func.called = False
return result
return f
然后你可以做
@norecurse
def f(some, arg, s):
do_stuff()
如果f
在运行时再次被调用,called
将会是True
并且它会引发异常。
于 2011-10-26T08:45:12.797 回答