异常链是一种通过在捕获到的异常上包装新的异常来处理异常的技术。原始异常被保存为新异常的一个属性(例如原因)。
在一个异常 'A' 的处理过程中,可能会引发另一个异常 'B'。为了调试问题,了解这两个异常是有用的。有时候,异常处理器有意地重新抛出异常也是有用的,要么是为了提供额外的信息,要么是为了将异常转换成另一种类型。
在 Python 3.x 中,可以实现异常链。如果在一个 except
部分中有任何未处理的异常,它将附带被处理的异常,并被包括在错误消息中。
示例
在下面的代码片段中,尝试打开一个不存在的文件会引发 FileNotFoundError
。这个异常被 except
块检测到了。而在处理过程中又引发了另一个异常。
try:
open("nofile.txt")
except OSError:
raise RuntimeError("无法处理错误")
它将产生以下输出:
Traceback (最近的调用最后):
File "/home/cg/root/64afcad39c651/main.py", line 2, in <module>
open("nofile.txt")
FileNotFoundError: [Errno 2] 没有这样的文件或目录: 'nofile.txt'
在处理上述异常的过程中,又发生了另一个异常:
Traceback (最近的调用最后):
File "/home/cg/root/64afcad39c651/main.py", line 4, in <module>
raise RuntimeError("无法处理错误")
RuntimeError: 无法处理错误
raise ... from
语句
如果你在 raise
语句中使用可选的 from
子句,它表示一个异常是另一个异常的直接后果。当你在转换异常时,这可能是有用的。from
关键字后的标记应该是异常对象。
示例
try:
open("nofile.txt")
except OSError as exc:
raise RuntimeError from exc
它将产生以下输出:
Traceback (最近的调用最后):
File "/home/cg/root/64afcad39c651/main.py", line 2, in <module>
open("nofile.txt")
FileNotFoundError: [Errno 2] 没有这样的文件或目录: 'nofile.txt'
上述异常是下列异常的直接原因:
Traceback (最近的调用最后):
File "/home/cg/root/64afcad39c651/main.py", line 4, in <module>
raise RuntimeError from exc
RuntimeError
raise ... from None
语句
如果我们使用 None
而不是异常对象作为 from
子句的一部分,那么在前面的例子中发现的自动异常链就会被禁用。
示例
try:
open("nofile.txt")
except OSError as exc:
raise RuntimeError from None
它将产生以下输出:
Traceback (最近的调用最后):
File "C:\Python311\hello.py", line 4, in <module>
raise RuntimeError from None
RuntimeError
__context__
和 __cause__
表达式
在 except
块中抛出异常将自动将捕获的异常添加到新异常的 __context__
属性中。同样,你也可以使用 raise ... from
语法将 __cause__
添加到任何异常中。
示例
try:
try:
raise ValueError("ValueError")
except ValueError as e1:
raise TypeError("TypeError") from e1
except TypeError as e2:
print("异常是", repr(e2))
print("它的 __context__ 是", repr(e2.__context__))
print("它的 __cause__ 是", repr(e2.__cause__))
它将产生以下输出:
异常是 TypeError('TypeError')
它的 __context__ 是 ValueError('ValueError')
它的 __cause__ 是 ValueError('ValueError')