Python 中 raise 和 raise/from 的使用方法
0. 参考资料
1. 代码比较
今天在看《Effective Python》的时候第一次见到 raise A from B
的用法,所以在网上查了一下。
下面用代码比较一下 raise
和 raise/from
的区别。
raise.py
# raise
try:
raise ValueError
except Exception as e:
raise IndexError
"""
Traceback (most recent call last):
File "raise.py", line 3, in <module>
raise ValueError
ValueError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "raise.py", line 5, in <module>
raise IndexError
IndexError
"""
raisefrom.py
# raise/from
try:
raise ValueError
except Exception as e:
raise IndexError from e
"""
Traceback (most recent call last):
File "raisefrom.py", line 3, in <module>
raise ValueError
ValueError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "raisefrom.py", line 5, in <module>
raise IndexError from e
IndexError
"""
上面的 raise
和 raise/from
都是放在 except
异常处理块中的。
可以观察到 raise
和 raise/from
最大的区别是异常提示信息不一样:
raise
是:During handling of the above exception, another exception occurred:
。
即“在处理上面的异常时,发生了另外一个异常:
”。- 而
raise/from
是:The above exception was the direct cause of the following exception:
。
即“上面的异常是接下来的异常的直接原因:
”。
2. 用法解释
2.1 raise
当在 except
块或者 finally
块中出现异常时(包括使用单独的 raise
重新抛出异常的情况),之前的异常会被附加到新异常的 __context__
属性上。
except
块中的语句叫做异常处理器exception handler
,它们是处理异常的语句。
而在其他任何地方抛出异常,都不会设置 __context__
属性。
这样打印出来的异常信息就会包含这么一句话:During handling of the above exception, another exception occurred:
。
2.2 raise A from B
raise A from B
语句用于连锁 chain
异常。
from
后面的 B
可以是:
- 异常类
- 异常实例
None
(Python 3.3
的新特性)
如果 B
是异常类或者异常实例,那么 B
会被设置为 A
的 __cause__
属性,表明 A异常
是由 B异常
导致的。
这样打印出来的异常信息就会包含这样一句话:The above exception was the direct cause of the following exception:
。
与此同时,在 Python 3.3
中 A异常
的 __suppress_context__
属性会被设置为 True
,这样就抑制了 A异常
的 __context__
属性,即忽略 __context__
属性。
于是 Python
就不会自动打印异常上下文 exception context
,而是使用 __cause__
属性来打印异常的引发者。
在 Python 3.3
中,B
还可以是 None
:raise A异常 from None
。
这样相当于把 __suppress_context__
属性设置为 True
,从而禁用了 __context__
属性,Python
不会自动展示异常上下文。
比如下面这段代码,注意到只显示了 IndexError
一个异常信息:
raisefromnone.py
# raise ... from None
# 禁用异常上下文属性
try:
raise ValueError
except Exception as e:
raise IndexError from None
"""
Traceback (most recent call last):
File "raisefromnone.py", line 6, in <module>
raise IndexError from None
IndexError
"""
3. 总结
在 except
或者 finally
块中使用 raise
和 raise/from
语句需要注意:
raise
会设置后面异常的__context__
属性为前面的异常。
异常信息中会有During handling of the above exception, another exception occurred:
。raise A异常 from B异常
会把A异常
的__cause__
属性设置为B异常
。
同时设置__suppress_context__
属性为True
,从而忽略__context__
属性,不打印异常上下文信息。
异常信息中会有The above exception was the direct cause of the following exception:
。raise A异常 from None
会设置A异常
的__suppress_context__
属性为True
,这样会忽略它的__context__
属性,不会自动显示异常上下文信息。
完成于 2018.11.21