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

前端 未结 2 938
旧时难觅i
旧时难觅i 2020-12-05 20:28

Let\'s say I have a Python function f and fhelp. fhelp is designed to call itself recursively. f should not be called rec

相关标签:
2条回答
  • 2020-12-05 20:59

    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.

    0 讨论(0)
  • 2020-12-05 21:11

    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
    
    0 讨论(0)
提交回复
热议问题