Piotr Dabkowski
Piotr Dabkowski

Reputation: 5939

Python recursion RuntimeError

def f1():
    f1()

We all know that calling this function in Python will produce RuntimeError: maximum recursion depth exceeded

I wrote its sligtly modified version:

def f2():
    try:
        f2()  #This line throws an error
    finally: #except works too
        f2()  #This line does not throw an error!

The second function runs forever without throwing RuntimeError. What's more, I was not able to stop it with CtrlC combination.

I dont understand why calling f2() does not throw RuntimeError. Can you explain it please?

Upvotes: 8

Views: 2124

Answers (2)

Martijn Pieters
Martijn Pieters

Reputation: 1121924

The exception is still being thrown, but before Python can show it you are calling f2() again.

So each time the exception is raised, you sneak in another call. That recursive call is allowed (because we are one step below the limit), we cross the limit, the exception is raised again, the finally handler sneaks in another call, almost ad infinitum.

CTRL-C doesn't end the program for the same reasons; an exception is raised (KeyboardInterrupt), but again the finally: handler sends you back into recursion.

You are now falling at such a velocity you entered orbit around the interpreter.

It all does end, but the finally handlers add an exponentially growing number of extra calls before the stack can fully unwind:

>>> import sys
>>> def f2(depth=0, final=0):
...     try:
...         print depth
...         f2(depth + 1, final)
...     finally:
...         print 'finally:', final
...         f2(depth, final + 1)
... 
>>> sys.setrecursionlimit(5)
>>> f2()
0
1
2
3
finally: 0
finally: 0
2
finally: 1
finally: 0
1
2
finally: 1
finally: 1
1
finally: 2
finally: 0
0
1
2
finally: 1
finally: 1
1
finally: 2
finally: 1
0
1
finally: 2
finally: 2
0
finally: 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in f2
  File "<stdin>", line 7, in f2
  File "<stdin>", line 7, in f2
  File "<stdin>", line 7, in f2
RuntimeError: maximum recursion depth exceeded

Upvotes: 4

mhlester
mhlester

Reputation: 23231

As the stack fills up, it calls f2 inside the try until it reaches the maximum recursion depth.

Once it's reached that, it raises a RuntimeError, which is handled by the finally

That in turn raises the same RuntimeError, but now to the earlier stack, which passes along to the finally call.

Inside there, it exceeds the maximum depth again.

When a KeyboardInterrupt is raised, the program moves on to the finally all the same, and doesn't exit.

It won't technically run forever, because there's only one finally. That said, (thanks to the comments), it allows exponentially more calls, which is pretty dang close to infinity. A recursion depth of 100 would turn into 2100 == 1267650600228229401496703205376.

If it took 1ms per call, it would take 465 billion years to complete. And that's just a depth of 100

Upvotes: 4

Related Questions