3

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?

1 Answer 1

3

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"
Sign up to request clarification or add additional context in comments.

2 Comments

So, just to clarify, the original exception never actually gets handled?
Correct, it is never handled.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.