且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Python 方法是否可以检查它是否已从自身内部调用?

更新时间:2023-11-10 19:12:28

使用 traceback 模块:

>>>导入回溯>>>def f(深度=0):...打印深度,traceback.print_stack()...如果深度

因此,如果堆栈中的任何条目表明代码是从 f 调用的,则该调用是(in)直接递归的.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:...引发异常,递归"...返回 f(*args, **kwargs)...返回函数...>>>@norecurse... def foo(depth=0):... 打印深度... foo(深度 + 1)...>>>富()0回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中文件<stdin>",第 5 行,在 func文件<stdin>",第 4 行,在 foo 中文件<stdin>",第 5 行,在 func例外:递归

Let's say I have a Python function f and fhelp. fhelp is designed to call itself recursively. f should not be called recursively. Is there a way for f to determine if it has been called recursively?

Use the traceback module for this:

>>> 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

So, if any entry in the stack indicates that the code was called from f, the call was (in)directly recursive. The traceback.extract_stack method gives you an easy access to this data. The if len(l[2] ... statement in the example below simply counts the number of exact matches of the name of the function. To make it even prettier (thanks to agf for the idea), you could make it into a decorator:

>>> 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