Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exceptions within exception handling in Python

I'm trying to understand how Python handles exceptions within exception handling. For example, consider the following:

try:
    try:
        1/0
    finally:
        raise Exception("Exception!")
except Exception as e:
    print(e)

My understanding is that both exceptions thrown by this code (both the ZeroDivisionError and the generic exception thrown in the finally block) should be "handled" by the outside except block...but how does Python decide which one to assign to e? Running the code on my machine, it seems that Python chooses to assign the "most recent" exception (the one thrown in the finally block) to e.

Is this generally true? Also, in a case like this where multiple exceptions might be thrown inside of error handling that are all handled by an outer except block, is there a way for the outer except block to step through each of the errors separately?

like image 260
Ang_d Avatar asked Feb 14 '26 05:02

Ang_d


1 Answers

The Python docs have this:

If an exception occurs during execution of the try clause, the exception may be handled by an except clause. If the exception is not handled by an except clause, the exception is re-raised after the finally clause has been executed.

So in your example, you don't catch the inner exception, this causes the finally block to execute (before re-raising the original exception). The exception in finally kicks it to the outside block before there is a chance to re-raise the original exception. The outside block never sees the divide-by-zero exception.

This is similar to returning from a function in finally:

def ex_test():
    try:
        try:
            1/0
        finally:
            return "finally"
    except Exception as e:
        print(e) # never gets here

ex_test()
# only prints "finally"
# never re-raises the exception

You can get some information about the original exception. From the docs:

When raising (or re-raising) an exception in an except or finally clause context is automatically set to the last exception caught; if the new exception is not handled the traceback that is eventually displayed will include the originating exception(s) and the final exception.

So:

try:
    try:
        1/0
    finally:
        raise Exception("Exception!")
except Exception as e:
    print(e.__context__)

# prints: "division by zero"
like image 199
Mark Avatar answered Feb 16 '26 18:02

Mark



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!