內建的例外

在 Python 中,所有例外必須是從 BaseException 衍生的類別的實例。在陳述式 try 搭配 except 子句裡提到一個特定的類別時,那個子句也會處理任何從該類別衍生的例外類別(但不會處理該類別衍生自的例外類別)。兩個不是由子類別關係關聯起來的例外類別永遠不相等,就算它們有相同的名稱也是如此。

此章節裡列出的內建例外可以從直譯器或內建函式產生。除了特別提到的地方之外,它們會有一個關聯值表示錯誤發生的詳細原因。這可能是一個字串,或者是一些資訊項目組成的元組(例如一個錯誤代碼及一個解釋該代碼的字串)。這個關聯值通常當作引數傳遞給例外類別的建構函式。

使用者的程式碼可以引發內建例外。這可以用來測試例外處理器或者用來回報一個錯誤條件,就像直譯器會引發相同例外的情況;但需要注意的是沒有任何方式可以避免使用者的程式碼引發不適當的錯誤。

可以從內建的例外類別定義新的例外子類別;程式設計師被鼓勵從 Exception 類別或其子類別衍生新的例外,而不是從 BaseException 來衍生。更多關於定義例外的資訊可以在 Python 教學中的使用者自定的例外裡取得。

例外的情境

三個例外物件上的屬性提供關於引發此例外的情境的資訊:

BaseException.__context__
BaseException.__cause__
BaseException.__suppress_context__

當引發一個新的例外而同時有另一個例外已經正在被處理時,這個新例外的 __context__ 屬性會自動被設成那個已處理的例外。當使用 exceptfinally 子句或 with 陳述式的時候例外會被處理。

這個隱含的例外情境可以透過使用 from 搭配 raise 來補充明確的原因:

raise new_exc from original_exc

from 後面的運算式必須是一個例外或 None。它將會被設定成所引發例外的 __cause__。設定 __cause__ 也隱含地設定 __suppress_context__ 屬性為 True,因此使用 raise new_exc from None 實際上會以新的例外取代舊的例外以利於顯示(例如轉換 KeyErrorAttributeError),同時保持舊的例外可以透過 __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(),會回傳實例的引數的表示,或者沒有引數的時候會回傳空字串。

args

提供給該例外建構函式的引數元組。一些內建的例外(像是 OSError)預期接受特定數量的引數並賦予該元組的每一個元素一個特別的意義,其他例外則通常用一個提供錯誤訊息的單一字串來呼叫。

with_traceback(tb)

此方法設定 tb 為該例外的新的回溯並回傳該例外物件。在 PEP 3134 的例外連鎖功能變得可用之前,此方法曾被更普遍使用。下面的範例顯示我們如何將 SomeException 的實例轉換為 OtherException 的實例同時保留回溯。一旦被引發,目前的 frame 會被加進 OtherException 的回溯,就像原來 SomeException 的回溯會發生的一樣,我們允許它被傳遞給呼叫者:

try:
    ...
except SomeException:
    tb = sys.exception().__traceback__
    raise OtherException(...).with_traceback(tb)
__traceback__

可寫入的欄位,儲存關聯到該例外的回溯物件。也可以參考 raise 陳述式

add_note(note)

新增字串 note 到例外的備註,在標準的回溯裡,備註出現在例外字串的後面。如果 note 不是字串則引發 TypeError

在 3.11 版被加入.

__notes__

該例外的備註串列,使用 add_note() 來新增。此屬性在 add_note() 被呼叫的時候建立。

在 3.11 版被加入.

exception Exception

所有內建、非系統退出 (non-system-exiting) 的例外都衍生自此類別。所有使用者定義的例外應該也要衍生自此類別。

exception ArithmeticError

各種運算錯誤所引發的那些內建例外:OverflowErrorZeroDivisionErrorFloatingPointError 的基底類別。

exception BufferError

緩衝 (buffer) 相關的操作無法被執行時會引發此例外。

exception LookupError

當使用在對映或序列上的鍵或索引是無效的時候所引發的例外:IndexErrorKeyError 的基底類別。這可以被 codecs.lookup() 直接引發。

實體例外

以下的例外是通常會被引發的例外。

exception AssertionError

assert 陳述式失敗的時候被引發。

exception AttributeError

當屬性參照(參考 Attribute references)或賦值失敗的時候被引發。(當物件根本不支援屬性參照或屬性賦值的時候,TypeError 會被引發。)

可選的僅限關鍵字引數 nameobj 會設定對應的屬性:

name

嘗試被存取的屬性名稱。

obj

存取指定屬性的物件。

在 3.10 版的變更: 新增 nameobj 屬性。

exception EOFError

input() 函式在沒有讀到任何資料而到達檔案結尾 (end-of-file, EOF) 條件的時候被引發。(注意:io.TextIOBase.read()io.IOBase.readline() 方法當達到 EOF 時會回傳空字串。)

exception FloatingPointError

目前沒有被使用。

exception GeneratorExit

generatorcoroutine 被關閉的時候被引發;參考 generator.close()coroutine.close()。此例外直接繼承自 BaseException 而不是 Exception,因為技術上來說這不是一個錯誤。

exception ImportError

import 陳述式嘗試載入模組遇到問題的時候會被引發。當 from ... import 裡的 "from list" 包含找不到的名稱時也會被引發。

可選的僅限關鍵字引數 namepath 設定對應的屬性:

name

嘗試引入 (import) 的模組名稱。

path

觸發此例外的任何檔案的路徑。

在 3.3 版的變更: 新增 namepath 屬性。

exception ModuleNotFoundError

ImportError 的子類別,當模組不能被定位的時候會被 import 所引發。當在 sys.modules 裡找到 None 時也會被引發。

在 3.6 版被加入.

exception IndexError

當序列的索引超出範圍的時候會被引發。(切片索引 (slice indices) 會默默地被截短使其能落在允許的範圍內;如果索引不是整數,TypeError 會被引發。)

exception KeyError

當對映(字典)的鍵無法在已存在的鍵的集合中被找到時會被引發。

exception KeyboardInterrupt

當使用者輸入中斷鍵 (interrupt key)(一般來說是 Control-CDelete)時會被引發。在執行過程中,會定期檢查是否產生中斷。此例外繼承自 BaseException 以防止意外地被捕捉 Exception 的程式碼所捕捉,而因此讓直譯器無法結束。

備註

捕捉 KeyboardInterrupt 需要特殊的考量。因為它可以在無法預期的時間點被引發,可能在某些情況下讓正在跑的程式處在一個不一致的狀態。一般來說最好讓 KeyboardInterrupt 越快結束程式越好,或者完全避免引發它。(參考 訊號處理程式與例外的說明。)

exception MemoryError

當一個操作用光了記憶體但情況還可能被修復 (rescued)(透過刪除一些物件)的時候被引發。關聯值是一個字串,表示什麼類型的(內部)操作用光了記憶體。需注意的是因為底層的記憶體管理架構(C 的 malloc() 函式),直譯器可能無法總是完整地從該情況中修復;僅管如此,它還是引發例外以讓堆疊回溯可以被印出,以防原因出在失控的程式。

exception NameError

當找不到本地或全域的名稱時會被引發。這只應用在不合格的名稱 (unqualified name) 上。關聯值是一個錯誤訊息,包含那個無法被找到的名稱。

可選的僅限關鍵字引數 name 設定對應的屬性:

name

嘗試被存取的變數名稱。

在 3.10 版的變更: 新增 name 屬性。

exception