內建的例外

在 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) 不相容。

CPython 實作細節: 為了效率,大部分的內建例外使用 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 屬性可以使用建構函式的僅限關鍵字 (keyword-only) 引數來設定。當被設定的時候,它們分別代表被嘗試存取的屬性名稱以及被以該屬性存取的物件。

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

exception EOFError

input() 函式在沒有讀到任何資料而到達檔案結尾 (end-of-file, EOF) 條件的時候被引發。(注意:io.IOBase.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 越快結束程式越好,或者完全避免引發它。(參考 Note on Signal Handlers and Exceptions。)

exception MemoryError

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

exception NameError

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

name 屬性可以使用僅限關鍵字引數來設定到建構函式。當被設定的時候它代表被嘗試存取的變數名稱。

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

exception NotImplementedError

此例外衍生自 RuntimeError。在使用者定義的基礎類別裡,當抽象方法要求衍生類別覆寫該方法時應該要引發此例外,或者當類別正在開發中,可用此例外表示還需要加入真正的實作。

備註

此例外不應該用來表示根本沒有要支援的運算子或方法 ── 在這個情況下可以讓該運算子或方法保持未定義,或者如果是子類別的話將其設成 None

備註

NotImplementedErrorNotImplemented 雖然有相似的名稱和目的但並不是可互換的。參考 NotImplemented 裡關於何時使用的細節。

exception OSError([arg])
exception OSError(errno, strerror[, filename[, winerror[, filename2]]])

當系統函式回傳系統相關錯誤,包含像"找不到檔案"或"硬碟已滿"的 I/O 失敗會引發此例外(而非不合法的引數或其他次要的錯誤)。

建構函式的第二種形式會設定以下描述的相對應屬性。如果沒有給定則屬性預設為 None。為了向後相容,如果傳入三個引數,args 屬性只會是包含建構函式前兩個引數的雙元素元組。

如同下面的作業系統例外所描述,實際上建構函式通常回傳 OSError 的子類別。會依據最後 errno 的值決定特定子類別。這個行為只發生在直接建構 OSError 或透過別名,且產生子類別的時候不會被繼承。

errno

從 C 變數 errno 而來的數值錯誤代碼。

winerror

在 Windows 下,這會提供你原生的 Windows 錯誤代碼。而 errno 屬性是一個該原生錯誤代碼對於 POSIX 來說的近似翻譯。

在 Windows 下,如果建構函式引數 winerror 是整數,則 errno 屬性會根據該 Windows 錯誤代碼來決定,且 errno 引數會被忽略。在其他平台上,winerror 引數會被忽略,而 winerror 屬性會不存在。

strerror

作業系統提供的對應錯誤訊息。在 POSIX 下會使用 C 函式 perror() 做格式化,而在 Windows 下會使用 FormatMessage()

filename
filename2

對於包含檔案系統路徑的例外(像是 open()os.unlink()),filename 是傳入函式的檔案名稱。對於包含兩個檔案系統路徑的函式(像是 os.rename()),filename2 對應到傳入函式的第二個檔案名稱。

在 3.3 版的變更: EnvironmentErrorIOErrorWindowsErrorsocket.errorselect.errormmap.error 已合併進 OSError,而建構函式可能會回傳子類別。

在 3.4 版的變更: filename 屬性現在是傳入函式的原始檔名,而不是從檔案系統編碼和錯誤處理函式編碼或解碼過的名稱。並且新增 filename2 建構函式引數與屬性。

exception OverflowError

當運算操作的結果太大而無法表示的時候會引發此例外。這不會發生在整數上(會改成引發 MemoryError 而不是放棄)。然而,因為一些歷史因素,OverflowError 有時候會因為整數在要求範圍之外而引發。因為在 C 裡面缺乏浮點數例外處理的標準化,大部分的浮點數運算都沒有被檢查。

exception PythonFinalizationError

此例外衍生自 RuntimeError。當一個操作在直譯器關閉(也稱作 Python 最終化 (Python finalization))期間被阻塞會引發此例外。

在 Python 最終化期間,能夠以 PythonFinalizationError 被阻塞的操作範例:

  • 建立新的 Python 執行緒。

  • os.fork()

也可以參閱 sys.is_finalizing() 函式。

在 3.13 版被加入: 在之前,會引發一般的 RuntimeError

exception RecursionError

此例外衍生自 RuntimeError。當直譯器偵測到超過最大的遞迴深度(參考 sys.getrecursionlimit())時會引發此例外。

在 3.5 版被加入: 在之前,會引發一般的 RuntimeError

exception ReferenceError

當一個被 weakref.proxy() 函式建立的弱參照代理 (weak reference proxy) 被用來存取已經被垃圾回收 (garbage collected) 的參照物屬性時會引發此例外。更多關於弱參照的資訊參考 weakref 模組。

exception RuntimeError

當偵測到一個不屬於任何其他種類的錯誤時會引發此例外。關聯值是一個表示確切什麼地方出錯的字串。

exception StopIteration

會被內建函式 next()iterator__next__() 方法引發,用來表示疊代器沒有更多項目可以產生。

value

此例外物件有單一屬性 value,當建構此例外時會以引數給定,預設為 None

generatorcoroutine 函式回傳時,新的 StopIteration 實例會被引發,而該函式的回傳值會被用來當作此例外建構函式的 value 參數。

如果產生器程式直接或間接引發 StopIteration,則其會被轉換成 RuntimeError(保留 StopIteration 作為新例外的成因)。

在 3.3 版的變更: 新增 value 屬性且產生器函式可以用它來回傳值。

在 3.5 版的變更: 透過 from __future__ import generator_stop 引入 RuntimeError 的轉換,參考 PEP 479

在 3.7 版的變更: 預設對所有程式啟用 PEP 479:在產生器引發的 StopIteration 錯誤會轉換成 RuntimeError

exception StopAsyncIteration

此例外必須被 asynchronous iterator 物件的 __anext__() 方法引發來停止疊代。

在 3.5 版被加入.

exception SyntaxError(message, details)

當剖析器遇到語法錯誤時會引發此例外。這可能發生在 import 陳述式、在呼叫內建函式 compile()exec()eval() 的時候,或者在讀取初始腳本或標準輸入(也包含互動式)的時候。

例外實例的 str() 只回傳錯誤訊息。Details 是個元組,其成員也能夠以分開的屬性取得。

filename

發生語法錯誤所在的檔案名稱。

lineno

發生錯誤所在檔案的列號。這是以 1 開始的索引:檔案第一列的 lineno 是 1。

offset

發生錯誤所在該列的欄號 (column)。這是以 1 開始的索引:該列第一個字元的 offset 是 1。

text

涉及該錯誤的原始程式碼文字。

end_lineno

發生錯誤所在檔案的結束列號。這是以 1 開始的索引:檔案第一列的 lineno 是 1。

end_offset

發生錯誤所在該結束列的欄號。這是以 1 開始的索引:該列第一個字元的 offset 是 1。

對於發生在 f-string 欄位的錯誤,訊息會以 "f-string: " 為前綴,而偏移量 (offset) 是從替代表達式建構的文字的偏移量。例如編譯 f'Bad {a b} field' 會得到這個 args 屬性:('f-string: ...', ('', 1, 2, '(a b)n', 1, 5))。

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

exception IndentationError

與不正確的縮排有關的語法錯誤的基礎類別。這是 SyntaxError 的子類別。

exception TabError

當縮排包含製表符號 (tab) 和空白的不一致用法時會引發此例外。這是 IndentationError 的子類別。

exception SystemError

當直譯器找到一個內部錯誤,但該情況看起來沒有嚴重到要讓它放棄所有的希望時會引發此例外。關聯值是一個表示什麼地方出錯的字串(以低階的方式表達)。

你應該向你的 Python 直譯器作者或維護者回報此錯誤。務必要回報該 Python 直譯器的版本(sys.version;這也會在互動式 Python 會話的開頭被印出)、確切的錯誤訊息(該例外的關聯值)及如果可能的話,觸發此錯誤的程式來源。

exception SystemExit

此例外會被 sys.exit() 函式引發。它繼承自 BaseException 而不是 Exception 因此不會被捕捉 Exception 的程式意外地捕捉。這允許例外可以正確地向上傳遞並導致直譯器結束。當它未被處理時,Python 直譯器會結束;不會印出堆疊回溯。建構函式接受跟傳入 sys.exit() 一樣的可選引數。如果該值是整數,它會指定系統的結束狀態(傳入 C 的 exit() 函式 );如果它是 None,結束狀態會是 0;如果它是其他型別(例如字串),則物件的值會被印出而結束狀態是 1。

sys.exit() 的呼叫會轉譯成例外讓負責清理的處理函式(try 陳述式的 finally 子句)可以被執行,且讓除錯器可以在不冒著失去控制的風險下執行腳本。如果在絕對有必要立即結束的情況(例如在子行程呼叫完 os.fork() 之後 )可以使用 os._exit() 函式。

code

傳入建構函式的結束狀態或錯誤訊息。(預設是 None。 )

exception TypeError

當一個操作或函式被用在不適合的型別的物件時會引發此例外。關聯值是一個字串,提供關於不相符型別的細節。

此例外可能被使用者程式碼引發,以表示並不支援物件上所嘗試的操作,且本來就無意這樣做。如果一個物件有意要支援某個給定的操作但尚未提供實作,該引發的正確例外是 NotImplementedError

傳入錯誤型別的引數(例如當預期傳入 int 卻傳入 list)應該要導致 TypeError,但傳入帶有錯誤值的引數(例如超出預期範圍的數值)應該要導致 ValueError

exception UnboundLocalError

當在函式或方法裡引用某個區域變數,但該變數尚未被繫結到任何值的時候會引發此例外。這是 NameError 的子類別。

exception UnicodeError

當 Unicode 相關的編碼或解碼錯誤發生時會引發此例外。這是 ValueError 的子類別。

UnicodeError 有屬性描述編碼或解碼錯誤。例如 err.object[err.start:err.end] 會提供讓編解碼器失敗的具體無效輸入。

encoding

引發錯誤的編碼名稱。

reason

描述特定編解碼器錯誤的字串。

object

編解碼器嘗試編碼或解碼的物件。

start

object 中無效資料的開始索引。

This value should not be negative as it is interpreted as an absolute offset but this constraint is not enforced at runtime.

end

object 中最後的無效資料後的索引。

This value should not be negative as it is interpreted as an absolute offset but this constraint is not enforced at runtime.

exception UnicodeEncodeError

在編碼當中發生 Unicode 相關錯誤時會引發此例外。這是 UnicodeError 的子類別。

exception UnicodeDecodeError

在解碼當中發生 Unicode 相關錯誤時會引發此例外。這是 UnicodeError 的子類別。

exception UnicodeTranslateError

在轉譯當中發生 Unicode 相關錯誤時會引發此例外。這是 UnicodeError 的子類別。

exception ValueError

當一個操作或函式收到引數是正確型別但是不適合的值,且該情況無法被更精確的例外例如 IndexError 所描述時會引發此例外。

exception ZeroDivisionError

當除法或模數運算 (modulo operation) 的第二個引數是 0 的時候會引發此例外。關聯值是一個字串,表示運算元及運算的類型。

以下例外是為了相容於之前版本而保留;從 Python 3.3 開始,它們是 OSError 的別名。

exception EnvironmentError
exception IOError
exception WindowsError

僅限於在 Windows 中使用。

作業系統例外

以下的例外是 OSError 的子類別,它們根據系統錯誤代碼來引發。

exception BlockingIOError

當設置為非阻塞操作的物件(例如 socket)上的操作將要阻塞時會引發此例外。對應到 errno EAGAINEALREADYEWOULDBLOCKEINPROGRESS

除了 OSError 的那些屬性之外,BlockingIOError 有多一個屬性:

characters_written

一個整數,內容為在其阻塞之前,已寫進串流的字元數。當使用 io 模組裡的緩衝 I/O 類別時這個屬性是可用的。

exception ChildProcessError

當子行程上的操作失敗時會引發此例外。對應到 errno ECHILD

exception ConnectionError

連線相關問題的基礎類別。

子類別有 BrokenPipeErrorConnectionAbortedErrorConnectionRefusedErrorConnectionResetError

exception BrokenPipeError

ConnectionError 的子類別,當嘗試寫入管道 (pipe) 同時另一端已經被關閉時會引發此例外,或者當嘗試寫入已關閉寫入的 socket 時也會引發。對應到 errno EPIPEESHUTDOWN

exception ConnectionAbortedError

ConnectionError 的子類別。當一個連線的嘗試被對等端點 (peer) 中斷時會引發此例外。對應到 errno ECONNABORTED

exception ConnectionRefusedError

ConnectionError 的子類別。當一個連線的嘗試被對等端點拒絕時會引發此例外。對應到 errno ECONNREFUSED

exception ConnectionResetError

ConnectionError 的子類別。當一個連線被對等端點重置時會引發此例外。對應到 errno ECONNRESET

exception FileExistsError

當嘗試建立已存在的檔案或目錄時會引發此例外。對應到 errno EEXIST

exception FileNotFoundError

當請求不存在的檔案或目錄時會引發此例外。對應到 errno ENOENT

exception InterruptedError

當系統呼叫被傳入的信號中斷時會引發此例外。對應到 errno EINTR

在 3.5 版的變更: 現在當 syscall 被信號中斷時 Python 會重試系統呼叫而不會引發 InterruptedError,除非信號處理器引發例外(理由可參考 PEP 475)。

exception IsADirectoryError

當在目錄上請求檔案操作(例如 os.remove())時會引發此例外。對應到 errno EISDIR

exception NotADirectoryError

當在某個不是目錄的東西上請求目錄操作(例如 os.listdir())時會引發此例外。在大多數的 POSIX 平台上,如果嘗試操作開啟或遍歷一個當作目錄的非目錄檔案也會引發此例外。對應到 errno ENOTDIR

exception PermissionError

當嘗試執行一個沒有合乎存取權限的操作時會引發此例外 — 例如檔案系統權限。對應到 errno EACCESEPERMENOTCAPABLE

在 3.11.1 版的變更: WASI 的 ENOTCAPABLE 現在對應到 PermissionError

exception ProcessLookupError

當給定的行程不存在時會引發此例外。對應到 errno ESRCH

exception TimeoutError

當系統函式在系統層級超時會引發此例外。對應到 errno ETIMEDOUT

在 3.3 版被加入: 加入以上所有的 OSError 子類別。

也參考

PEP 3151 — 改寫作業系統與 IO 例外階層

警告

以下的例外是當作警告的種類使用;更多細節參考 Warning Categories 文件。

exception Warning

警告種類的基礎類別。

exception UserWarning

使用者程式碼產生的警告的基礎類別。

exception DeprecationWarning

關於已棄用功能的警告的基礎類別,且當那些警告是針對其他 Python 開發者。

會被預設的警告過濾器忽略,在 __main__ 模組裡除外 (PEP 565)。啟用 Python 開發模式會顯示此警告。

棄用原則描述在 PEP 387 裡。

exception PendingDeprecationWarning

關於過時且預期未來要被棄用,但目前尚未被棄用的功能的警告的基礎類別。

因為發出關於可能即將被棄用的警告是不尋常的,此類別很少被使用,而對已經被棄用的情況會優先使用 DeprecationWarning

會被預設的警告過濾器忽略。啟用 Python 開發模式會顯示此警告。

棄用原則描述在 PEP 387 裡。

exception SyntaxWarning

關於可疑語法的警告的基礎類別。

exception RuntimeWarning

關於可疑執行環境行為的警告的基礎類別。

exception FutureWarning

關於已棄用功能的警告的基礎類別,且當那些警告是針對以 Python 寫的應用程式的終端使用者。

exception ImportWarning

關於在模組引入的可能錯誤的警告的基礎類別。

會被預設的警告過濾器忽略。啟用 Python 開發模式會顯示此警告。

exception UnicodeWarning

Unicode 相關警告的基礎類別。

exception EncodingWarning

編碼相關警告的基礎類別。

細節參考選擇性加入的編碼警告

在 3.10 版被加入.

exception BytesWarning

bytesbytearray 相關警告的基礎類別。

exception ResourceWarning

資源用法相關警告的基礎類別。

會被預設的警告過濾器忽略。啟用 Python 開發模式會顯示此警告。

在 3.2 版被加入.

例外群組

當需要引發多個不相關例外時會使用下列的類別。它們是例外階層的一部分所以可以像所有其他例外一樣使用 except 來處理。此外,它們會以包含的例外型別為基礎來比對其子群組而被 except* 辨認出來。

exception ExceptionGroup(msg, excs)
exception BaseExceptionGroup(msg, excs)

這兩個例外型別都將例外包裝在序列 excs 中。msg 參數必須是字串。這兩個類別的差異是 BaseExceptionGroup 擴充了 BaseException 且可以包裝任何例外,而 ExceptionGroup 擴充了 Exception 且只能包裝 Exception 的子類別。這個設計使得 except Exception 可以捕捉 ExceptionGroup 但不能捕捉 BaseExceptionGroup

如果所有包含的例外都是 Exception 實例,BaseExceptionGroup 建構函式會回傳 ExceptionGroup 而不是 BaseExceptionGroup,因此可以被使用來讓這樣的選擇自動化。另一方面來說,如果任何包含的例外不是 Exception 的子類別,ExceptionGroup 建構函式會引發 TypeError

message

建構函式的 msg 引數。這是一個唯讀的屬性。

exceptions

指定給建構函式 excs 序列中的例外組成的元組。這是一個唯讀的屬性。

subgroup(condition)

回傳只包含從現有群組比對到 condition 的例外的例外群組,或者當結果為空時回傳 None

條件式可以是一個例外型別或是例外型別的元組,在此情況下,每個例外都會使用與 except 子句中使用的相同檢查方法來檢查是否有匹配。條件式也可以是一個可呼叫物件(除了型別物件之外),其接受一個例外作為單一引數,而如果該例外應該在子群組中就回傳 true。

現有例外的巢狀結構會保留在結果裡,其 message__traceback____cause____context____notes__ 欄位的值也一樣。空的巢狀群組會從結果裡排除。

條件會對巢狀例外群組裡的所有例外做檢查,包括頂層及任何巢狀的例外群組。如果條件對這樣的例外群組為 true,它會被完整包含在結果裡。

在 3.13 版被加入: condition 可以是任何不是型別物件的可呼叫物件。

split(condition)

subgroup() 一樣,但回傳一對 (match, rest),其中 matchsubgroup(condition)rest 是剩下沒有比對到的部分。

derive(excs)

回傳有相同 message 但將例外包裝在 excs 的例外群組。

此方法被 subgroup()split() 使用,被用來在各種情境下拆分例外群組。子類別需要覆寫它來讓 subgroup()split() 回傳子類別而不是 ExceptionGroup 的實例。

subgroup()split() 會從原始的例外群組複製 __traceback____cause____context____notes__ 欄位到 derive() 所回傳的例外群組上,因此這些欄位不需要被 derive() 更新。

>>> class MyGroup(ExceptionGroup):
...     def derive(self, excs):
...         return MyGroup(self.message, excs)
...
>>> e = MyGroup("eg", [ValueError(1), TypeError(2)])
>>> e.add_note("a note")
>>> e.__context__ = Exception("context")
>>> e.__cause__ = Exception("cause")
>>> try:
...    raise e
... except Exception as e:
...    exc = e
...
>>> match, rest = exc.split(ValueError)
>>> exc, exc.__context__, exc.__cause__, exc.__notes__
(MyGroup('eg', [ValueError(1), TypeError(2)]), Exception('context'), Exception('cause'), ['a note'])
>>> match, match.__context__, match.__cause__, match.__notes__
(MyGroup('eg', [ValueError(1)]), Exception('context'), Exception('cause'), ['a note'])
>>> rest, rest.__context__, rest.__cause__, rest.__notes__
(MyGroup('eg', [TypeError(2)]), Exception('context'), Exception('cause'), ['a note'])
>>> exc.__traceback__ is match.__traceback__ is rest.__traceback__
True

需注意 BaseExceptionGroup 定義了 __new__(),因此需要不同建構函式簽名的子類別需要覆寫它而不是 __init__()。例如下面定義了一個例外群組子類別接受 exit_code 並從中建構群組的訊息。:

class Errors(ExceptionGroup):
   def __new__(cls, errors, exit_code):
      self = super().__new__(Errors, f"exit code: {exit_code}", errors)
      self.exit_code = exit_code
      return self

   def derive(self, excs):
      return Errors(excs, self.exit_code)

ExceptionGroup 一樣,任何 BaseExceptionGroup 的子類別且也是 Exception 的子類別只能包裝 Exception 的實例。

在 3.11 版被加入.

例外階層

內建例外的類別階層如下:

BaseException
 ├── BaseExceptionGroup
 ├── GeneratorExit
 ├── KeyboardInterrupt
 ├── SystemExit
 └── Exception
      ├── ArithmeticError
      │    ├── FloatingPointError
      │    ├── OverflowError
      │    └── ZeroDivisionError
      ├── AssertionError
      ├── AttributeError
      ├── BufferError
      ├── EOFError
      ├── ExceptionGroup [BaseExceptionGroup]
      ├── ImportError
      │    └── ModuleNotFoundError
      ├── LookupError
      │    ├── IndexError
      │    └── KeyError
      ├── MemoryError
      ├── NameError
      │    └── UnboundLocalError
      ├── OSError
      │    ├── BlockingIOError
      │    ├── ChildProcessError
      │    ├── ConnectionError
      │    │    ├── BrokenPipeError
      │    │    ├── ConnectionAbortedError
      │    │    ├── ConnectionRefusedError
      │    │    └── ConnectionResetError
      │    ├── FileExistsError
      │    ├── FileNotFoundError
      │    ├── InterruptedError
      │    ├── IsADirectoryError
      │    ├── NotADirectoryError
      │    ├── PermissionError
      │    ├── ProcessLookupError
      │    └── TimeoutError
      ├── ReferenceError
      ├── RuntimeError
      │    ├── NotImplementedError
      │    ├── PythonFinalizationError
      │    └── RecursionError
      ├── StopAsyncIteration
      ├── StopIteration
      ├── SyntaxError
      │    └── IndentationError
      │         └── TabError
      ├── SystemError
      ├── TypeError
      ├── ValueError
      │    └── UnicodeError
      │         ├── UnicodeDecodeError
      │         ├── UnicodeEncodeError
      │         └── UnicodeTranslateError
      └── Warning
           ├── BytesWarning
           ├── DeprecationWarning
           ├── EncodingWarning
           ├── FutureWarning
           ├── ImportWarning
           ├── PendingDeprecationWarning
           ├── ResourceWarning
           ├── RuntimeWarning
           ├── SyntaxWarning
           ├── UnicodeWarning
           └── UserWarning