內建的例外¶
在 Python 中,所有例外必須是從 BaseException 衍生的類別的實例。在陳述式 try 搭配 except 子句裡提到一個特定的類別時,那個子句也會處理任何從該類別衍生的例外類別(但不會處理該類別衍生自的例外類別)。兩個不是由子類別關係關聯起來的例外類別永遠不相等,就算它們有相同的名稱也是如此。
此章節裡列出的內建例外可以從直譯器或內建函式產生。除了特別提到的地方之外,它們會有一個關聯值表示錯誤發生的詳細原因。這可能是一個字串,或者是一些資訊項目組成的元組(例如一個錯誤代碼及一個解釋該代碼的字串)。這個關聯值通常當作引數傳遞給例外類別的建構函式。
使用者的程式碼可以引發內建例外。這可以用來測試例外處理器或者用來回報一個錯誤條件,就像直譯器會引發相同例外的情況;但需要注意的是沒有任何方式可以避免使用者的程式碼引發不適當的錯誤。
可以從內建的例外類別定義新的例外子類別;程式設計師被鼓勵從 Exception 類別或其子類別衍生新的例外,而不是從 BaseException 來衍生。更多關於定義例外的資訊可以在 Python 教學中的使用者自定的例外裡取得。
例外的情境¶
三個例外物件上的屬性提供關於引發此例外的情境的資訊:
- BaseException.__context__¶
- BaseException.__cause__¶
- BaseException.__suppress_context__¶
當引發一個新的例外而同時有另一個例外已經正在被處理時,這個新例外的
__context__屬性會自動被設成那個已處理的例外。當使用except或finally子句或with陳述式的時候例外會被處理。這個隱含的例外情境可以透過使用
from搭配raise來補充明確的原因:raise new_exc from original_exc
在
from後面的運算式必須是一個例外或None。它將會被設定成所引發例外的__cause__。設定__cause__也隱含地設定__suppress_context__屬性為True,因此使用raise new_exc from None實際上會以新的例外取代舊的例外以利於顯示(例如轉換KeyError為AttributeError),同時保持舊的例外可以透過__context__取得以方便 debug 的時候檢查。預設的回溯 (traceback) 顯示程式碼會顯示這些連鎖的例外 (chained exception) 加上例外本身的回溯。當存在的時候,在
__cause__中明確地連鎖的例外總是會被顯示。而在__context__中隱含地連鎖的例外只有當__cause__是None且__suppress_context__是 false 時才會顯示。在任一種情況下,例外本身總是會顯示在任何連鎖例外的後面,因此回溯的最後一列總是顯示最後一個被引發的例外。
繼承自內建的例外¶
使用者的程式碼可以建立繼承自例外型別的子類別。建議一次只繼承一種例外型別以避免在基底類別之間如何處理 args 屬性的任何可能衝突,以及可能的記憶體佈局 (memory layout) 不相容。
為了效率,大部分的內建例外使用 C 來實作,參考 Objects/exceptions.c。一些例外有客製化的記憶體佈局,使其不可能建立一個繼承多種例外型別的子類別。型別的記憶體佈局是實作細節且可能會在不同 Python 版本間改變,造成未來新的衝突。因此,總之建議避免繼承多種例外型別。
基底類別 (base classes)¶
以下的例外大部分被用在當作其他例外的基底類別。
- exception BaseException¶
所有內建例外的基底類別。這不是為了讓使用者定義的類別直接繼承(可以使用
Exception)。如果在這個類別的實例上呼叫str(),會回傳實例的引數的表示,或者沒有引數的時候會回傳空字串。- with_traceback(tb)¶
此方法設定 tb 為該例外的新的回溯並回傳該例外物件。在 PEP 3134 的例外連鎖功能變得可用之前,此方法曾被更普遍使用。下面的範例顯示我們如何將
SomeException的實例轉換為OtherException的實例同時保留回溯。一旦被引發,目前的 frame 會被加進OtherException的回溯,就像原來SomeException的回溯會發生的一樣,我們允許它被傳遞給呼叫者:try: ... except SomeException: tb = sys.exception().__traceback__ raise OtherException(...).with_traceback(tb)
- __notes__¶
該例外的備註串列,使用
add_note()來新增。此屬性在add_note()被呼叫的時候建立。在 3.11 版被加入.
- exception Exception¶
所有內建、非系統退出 (non-system-exiting) 的例外都衍生自此類別。所有使用者定義的例外應該也要衍生自此類別。
- exception ArithmeticError¶
各種運算錯誤所引發的那些內建例外:
OverflowError、ZeroDivisionError、FloatingPointError的基底類別。
- exception BufferError¶
當緩衝 (buffer) 相關的操作無法被執行時會引發此例外。
- exception LookupError¶
當使用在對映或序列上的鍵或索引是無效的時候所引發的例外:
IndexError、KeyError的基底類別。這可以被codecs.lookup()直接引發。
實體例外¶
以下的例外是通常會被引發的例外。
- exception AttributeError¶
當屬性參照(參考 Attribute references)或賦值失敗的時候被引發。(當物件根本不支援屬性參照或屬性賦值的時候,
TypeError會被引發。)可選的僅限關鍵字引數 name 和 obj 會設定對應的屬性:
- name¶
嘗試被存取的屬性名稱。
- obj¶
存取指定屬性的物件。
- exception EOFError¶
當
input()函式在沒有讀到任何資料而到達檔案結尾 (end-of-file, EOF) 條件的時候被引發。(注意:io.TextIOBase.read()和io.IOBase.readline()方法當達到 EOF 時會回傳空字串。)
- exception FloatingPointError¶
目前沒有被使用。
- exception GeneratorExit¶
當 generator 或 coroutine 被關閉的時候被引發;參考
generator.close()和coroutine.close()。此例外直接繼承自BaseException而不是Exception,因為技術上來說這不是一個錯誤。