Detecting recursion loops

robert no-spam at no-spam-no-spam.invalid
Wed Nov 29 13:20:19 EST 2006


Carl Banks wrote:
> robert wrote:
>> My code does recursion loops through a couple of functions. Due to problematic I/O input this leads sometimes to "endless" recursions and after expensive I/O to the Python recursion exception.
>> What would be a good method to detect recursion loops and stop it by user-Exception (after N passes or some complex criteria) without passing a recursion counter parameter through all the funcs?
> 
> 
> 1. You could catch RuntimeError at the top, check whether it's
> recursion depth exception, and raise a user exception if it is.

thats what happens now anyway. need to limit this kind of recursion.

> 2. Consider whether you're unwittingly trying to cover up a bug.  ISTM
> no matter how problematic the input is, you should at least be able to
> make progress on it.  Are you getting this error because, say, you're
> not incrementing a counter somewhere, and thus recalling a function
> with the same arguments again?

the "bug" comes in from the I/O input. its about to stop it in non-simple recursion (through more functions calls)

> 3. Also consider whether you could rewrite the code to be
> non-recursive.  Usually when I process input recursively, the input is
> allowed to be arbitrarily deeply nested.  (In that case I think it
> would be a mistake to arbitrarily limit depth.)   But it sounds to me
> like your input might be inherently non-nestable.  If that's the case,
> it might be possible to get rid of the recursion altogether, or at
> least to put in error checking that detects when input is at an invalid
> depth.
> 
> 4. If those concerns don't apply, and you do need to detect recursion,
> I'd suggest using a global dictionary to track function calls.  If you
> have a function parse_something that you want to track, you could
> define a dict like this:
> 
> _call_count = { parse_something: 0 }
> 
> And change parse_something to adjust its own counter:
> 
> def parse_something():
>     _call_count[parse_something] += 1
>     check_invalid_recursion()
>     ....
>     _call_count[parse_something] -= 1
> 
> (You could define a decorator to do this more easily; that's left as an
> excercise.)
> 
> The check_invalid_recursion() function would inspect _call_count and
> raise an exception based on any criteria you want.

thats possibly the right practical/fast possibility, I end so far with. As its threaded, a try-finally protected counter on a TLS _func_recccount[thread.get_ident()]

> 5. In CPython, you could just inpect the stack frame and look for
> duplicated function calls.  See the documentation for sys._getframe.
> 
> 
> Carl Banks
> 



More information about the Python-list mailing list