Why does code that in 3.10 throws a RecursionError as expected not throw in earlier versions?

Question:

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()
Asked By: Axeltherabbit

||

Answers:

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.

Answered By: Numerlor