¿Puede un método Python verificar si ha sido llamado desde dentro de sí mismo?

Digamos que tengo una función Python f y fhelp . fhelp está diseñado para llamarse a sí mismo de forma recursiva. f no debe ser llamado recursivamente. ¿Hay alguna manera para que f determine si se ha llamado recursivamente?

Utilice el módulo de rastreo para esto:

 >>> import traceback >>> def f(depth=0): ... print depth, traceback.print_stack() ... if depth < 2: ... f(depth + 1) ... >>> f() 0 File "", line 1, in  File "", line 2, in f None 1 File "", line 1, in  File "", line 4, in f File "", line 2, in f None 2 File "", line 1, in  File "", line 4, in f File "", line 4, in f File "", line 2, in f None 

Entonces, si alguna entrada en la stack indica que el código fue llamado desde f , la llamada fue (en) directamente recursiva. El método traceback.extract_stack le brinda un acceso fácil a estos datos. La statement if len(l[2] ... en el ejemplo a continuación simplemente cuenta el número de coincidencias exactas del nombre de la función. Para hacerlo aún más bonito (gracias a agf por la idea), podría convertirlo en un decorador:

 >>> 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 "", line 1, in  File "", line 5, in func File "", line 4, in foo File "", line 5, in func Exception: Recursed 

Podrías usar una bandera puesta por un decorador:

 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 

Entonces puedes hacer

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

y si se vuelve a llamar a f mientras se está ejecutando, se called True y generará una excepción.