Python 中 raise 和 raise/from 的區別
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