Can a Python method check if it has been called from within itself?

走远了吗. 提交于 2019-11-26 23:10:28

问题


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?


回答1:


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



回答2:


You could use a flag set by a decorator:

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

Then you can do

@norecurse
def f(some, arg, s):
    do_stuff()

and if f gets called again while it's running, called will be True and it will raise an exeption.



来源:https://stackoverflow.com/questions/7900345/can-a-python-method-check-if-it-has-been-called-from-within-itself

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!