异常链:获取链中前序异常的正确方式是什么?
Exception.__context__ the Correct Way to Access Predecessor Exceptions in an Exception Chain? Great question—this is a common point of confusion when working with Python's exception chaining, so let's unpack it step by step.
First: Is __context__ a valid way to access predecessor exceptions?
Yes, using __context__ is correct and officially recognized for accessing the implicit exception chain. Here's the breakdown:
- When you raise a new exception inside an
exceptblock without using theraise ... fromsyntax, Python automatically sets the new exception's__context__attribute to reference the original (caught) exception. This creates an implicit exception chain. - Unlike
__cause__(which is set explicitly viaraise NewException from OriginalException),__context__handles the "accidental" chaining that happens when exceptions are raised in response to another without explicit linking.
This attribute is part of Python's standard exception API, and the official docs do confirm its purpose for holding implicit predecessor exception references.
Second: Can __context__ contain non-exception instances?
No, you don't need to worry about non-exception values in __context__. By Python's design:
- The attribute is either set to an instance of a class inheriting from
BaseException(the parent class of all exceptions in Python) orNone(if there's no preceding exception in the chain). - Python's internal exception-handling logic only assigns valid exception objects to this attribute, so any non-
Nonevalue you get from__context__is guaranteed to be an exception instance.
A Note on Safe Traversal of Full Exception Chains
While __context__ works for implicit chains, a complete exception chain might include both implicit (__context__) and explicit (__cause__) links. To safely traverse the entire chain, you should check both attributes, prioritizing __cause__ first (since it represents an intentional, explicit chain):
def traverse_exception_chain(exception): current_exc = exception while current_exc: yield current_exc # Prioritize explicit cause over implicit context current_exc = current_exc.__cause__ or current_exc.__context__
This function will yield every exception in the chain, whether linked explicitly or implicitly.
内容的提问来源于stack exchange,提问作者ardabro

