1

I don't understand the meaning of the last sentence below:

If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. The finally clause is executed. If there is a saved exception it is re-raised at the end of the finally clause. If the finally clause raises another exception, the saved exception is set as the context of the new exception.

Questions

  1. Could someone please explain the meaning of the text in bold?

  2. Also, what object is saved if an exception occurs in an except clause? Does except's exception replace try's?

When I try raising an exception in except, both exceptions appear in the output:

try:
    1/0
except ZeroDivisionError:
    raise Exception("raised in except clause")

#-------------------------- Output ----------------------------
Traceback (most recent call last):

  File "C:\Users\...\try.py", line 2, in <cell line: 1>
    1/0

ZeroDivisionError: division by zero


During handling of the above exception, another exception occurred:

Traceback (most recent call last):

  File "C:\Users\...\try.py", line 4, in <cell line: 1>
    raise Exception("raised in except clause")

Exception: raised in except clause

The same happens when I raise it in finally (same input and output as above, but with "finally" in place of "except").

user51462
  • 1,658
  • 2
  • 13
  • 41
  • 1
    [This answer](https://stackoverflow.com/questions/6278426/raising-exceptions-when-an-exception-is-already-present-in-python-3/14826590#14826590) explains exactly what you are after - the object being saved is the previous exception(s) and that is attached as the `__context__` of the new exception. – metatoaster Aug 12 '22 at 03:26
  • I see, I'm still a little hazy on which exception is saved. My understanding is that if an unhandled exception occurs in any of the clauses, the corresponding exception object is temporarily saved. If, while this exception is outstanding, another unhandled exception occurs (e.g. in an `except` or `finally` or in the `else` of a `try` in the current `try`’s `except`), then the new exception is saved instead and its `__context__` attribute is set to the old exception. **Is this correct?** – user51462 Aug 12 '22 at 10:15
  • By raising `Exception("raised in except clause")` (not sure why you put it as "saved") inside the `except ZeroDivisionError` block, it will have an attribute `__context__` that points to the `ZeroDivisionError` instance, which a subsequent `try.. except` block surroundingthat code example can catch or see, otherwise it is printed via the `Traceback`. This is explained [in this answer](https://stackoverflow.com/a/24752607) which links to [this documentation](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement). – metatoaster Aug 13 '22 at 01:22
  • Thanks for getting back @metatoaster. The "saved" thing was just me trying to reconcile the quote in my post ("If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved.") to the one on execution contexts in your first link ("If the finally clause raises another exception, the saved exception is set as the context of the new exception."). I think I was reading it incorrectly - both exception objects are saved with the newer one's `__context__` set to the older one. – user51462 Aug 13 '22 at 01:34
  • Correct, and exceptions raised any subsequent outer `try..except/finally` blocks will take the inner exception and add to the most recently raised exception `.__context__` attribute. Python's exception reporting roughly [follows this rough recursive algorithm](https://peps.python.org/pep-3134/#enhanced-reporting) to find the most innermost `.__context__`, which would print that first, before backing up (hence the very first exception is printed first). – metatoaster Aug 13 '22 at 01:40

0 Answers0