Используйте для этого модуль traceback :
>>> 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
, вызов был (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:
... 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