Home > Mobile >  Why does this Python code behave so weirdly?
Why does this Python code behave so weirdly?

Time:10-15

To start I tried this

def x():
   try:
      1/0 # just an division error to get an exception
   except:
      x()

And this code behaves normally in 3.10 and I get RecursionError: maximum recursion depth exceeded as I expected but 3.8 goes into a stack overflow and doesn't handle the recursion error properly. But I did remember that there was RecursionError in older versions of Python too, so I tried

def x(): x()

And this gives back RecursionError in both versions of Python.

It's as if (in the first snippet) the recursion error is never thrown in the except but the function called and then the error thrown at the first instruction of the function called but handled by the try-except.

I then tried something else:

def x():
   try:
      x()
   except:
      x()

This is even weirder in some way, stack overflow below 3.10 but it get stuck in the loop in 3.10

Can you explain this behavior?

UPDATE @MisterMiyagi found a even stranger behavior, adding a statement in the except in <=python3.9 doesn't result in a stackoverflow

def x():
   try:
      1/0
   except:
      print("")
      x()

CodePudding user response:

The different behaviors for 3.10 and other versions seem to be because of a Python issue (python/cpython#86666), you can also see the correct error on Python 2.7.

The print "fixes" things because it makes Python check the recursion limit again, and through a path that is presumably not broken. You can see the code where it does that here, it also skips the repeated check if the object supports the Vectorcall calling protocol, so things like int keep the fatal error.

CodePudding user response:

Your exception is too broad, you should specify what type of exception you catch like this:

def x():
    try:
        1 / 0  # just an division error to get an exception
    except ZeroDivisionError:
        x()

try:
    x()
except RecursionError:
    print("You got an recursion error")

In your code, all the exceptions are caught, also the RecursionErrors. My guess is that this may lead that also the recursion errors go the second branch, keep calling your x function. Apparently in 3.10 this is fixed.

In general, the advice is to always include a type of error you want to catch. That your second version gets stuck is because x is always called, with and without recursion error, so you get in an infinite loop.

If you want to catch both the ZeroDivisionError and the RecursionError, you have to put the try/except for the Recursion error around your function call

  • Related