Python - 异常链接



异常链接

异常链接是一种处理异常的技术,通过在将捕获的异常包装到新异常中后重新引发该异常。原始异常将保存为新异常的属性 (如 cause) 。

在处理一个异常 'A' 期间,可能会发生另一个异常 'B'。了解这两个异常对于调试问题非常有用。有时,异常处理程序故意重新引发异常很有用,以提供额外信息或将异常转换为另一种类型。

在 Python 3.x 中,可以实现异常链接。如果 except 节内有任何未处理的异常,则会将正在处理的异常附加到该节并包含在错误消息中。

在下面的代码段中,尝试打开不存在的文件会引发 FileNotFoundError。它由 except 块检测到。在处理时引发另一个异常。


try:
	 	open("nofile.txt")
except OSError:
	 	raise RuntimeError("unable to handle error")

它将产生以下输出 -

Traceback (most recent call last):
File "/home/cg/root/64afcad39c651/main.py", line 2, in <module>
open("nofile.txt")
FileNotFoundError: [Errno 2] No such file or directory: 'nofile.txt'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/cg/root/64afcad39c651/main.py", line 4, in <module>
raise RuntimeError("unable to handle error")
RuntimeError: unable to handle error

raise . . from 语句

如果在 raise 语句中使用可选的 from 子句,则表示异常是另一个异常的直接结果。这在转换异常时非常有用。关键字后面的标记 from 应该是 exception 对象。


try:
	 	open("nofile.txt")
except OSError as exc:
	 	raise RuntimeError from exc

它将产生以下输出 -

Traceback (most recent call last):
File "/home/cg/root/64afcad39c651/main.py", line 2, in <module>
open("nofile.txt")
FileNotFoundError: [Errno 2] No such file or directory: 'nofile.txt'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/home/cg/root/64afcad39c651/main.py", line 4, in <module>
raise RuntimeError from exc
RuntimeError

raise . . from None 语句

如果我们在 from 子句中使用 None 而不是 exception object,则会禁用在前面的示例中发现的自动异常链接。


try:
	 	open("nofile.txt")
except OSError as exc:
	 	raise RuntimeError from None

它将产生以下输出 -

Traceback (most recent call last):
File "C:\Python311\hello.py", line 4, in <module>
raise RuntimeError from None
RuntimeError

__context__ 和 __cause__ 表达式

在 except 块中引发异常会自动将捕获的异常添加到新异常的 __context__ 属性中。同样,__cause__您也可以使用表达式 raise ...from 语法。


try:
	 	try:
	 	 	 raise ValueError("ValueError")
	 	except ValueError as e1:
	 	 	 raise TypeError("TypeError") from e1
except TypeError as e2:
	 	print("The exception was", repr(e2))
	 	print("Its __context__ was", repr(e2.__context__))
	 	print("Its __cause__ was", repr(e2.__cause__))

它将产生以下输出 -

The exception was TypeError('TypeError')
Its __context__ was ValueError('ValueError')
Its __cause__ was ValueError('ValueError')