Python context in Implicit Exception Chaining
This article explains the purpose and contents of the
__context__ attribute in Python's exception handling
mechanism, specifically during implicit exception chaining. It covers
what object is assigned to __context__, the conditions
under which the Python runtime populates it, and how it directly
influences the tracebacks displayed during unhandled errors.
What is Stored in
__context__?
In Python, the __context__ attribute of an implicitly
chained exception stores a reference to the previous exception
instance that was active when the new exception occurred.
Whenever an unhandled exception is raised inside an
except block or a finally clause, Python
automatically preserves the context of the original failure. The newly
raised exception's __context__ attribute is set directly to
the original exception object, creating a linked history of errors.
How Implicit Chaining Works
Implicit exception chaining happens automatically without requiring
the from keyword. Consider the following example:
try:
1 / 0
except ZeroDivisionError as original_error:
# A new exception occurs while handling ZeroDivisionError
int("invalid_number")In this code:
- A
ZeroDivisionErroris raised. - Inside the
exceptblock, Python attempts to runint("invalid_number"), which raises aValueError. - Because the
ValueErrorwas raised whileZeroDivisionErrorwas actively being handled, Python automatically assigns theZeroDivisionErrorinstance toValueError.__context__.
You can inspect this attribute programmatically:
try:
try:
1 / 0
except ZeroDivisionError:
int("invalid_number")
except ValueError as second_error:
print(type(second_error.__context__))
# Output: <class 'ZeroDivisionError'>
print(second_error.__context__)
# Output: division by zeroTraceback Representation
When an exception with a populated __context__ reaches
the top of the call stack unhandled, Python's default traceback printer
displays both exceptions in chronological order.
Between the tracebacks, Python inserts the following message:
During handling of the above exception, another exception occurred:
This diagnostic output informs the developer that the subsequent error was not an isolated incident, but occurred while attempting to recover from or clean up after the primary error.
__context__ vs.
__cause__
Python differentiates between implicit and explicit exception chaining using two distinct attributes:
__context__(Implicit Chaining): Populated automatically by the interpreter whenever an exception occurs during the handling of another exception.__cause__(Explicit Chaining): Populated only when using theraise NewException from OriginalExceptionsyntax.
When explicit chaining is used (raise ... from ...),
Python sets __cause__ to the specified exception and sets
__suppress_context__ = True. This signals the traceback
printer to show the message
"The above exception was the direct cause of the following exception:"
instead of the implicit context message. If no explicit cause is
provided, __cause__ remains None, and the
interpreter falls back to displaying __context__.