內建的例外¶
在 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,因為技術上來說這不是一個錯誤。
- exception ImportError¶
當
import陳述式嘗試載入模組遇到問題的時候會被引發。當from ... import裡的 "from list" 包含找不到的名稱時也會被引發。可選的僅限關鍵字引數 name 和 path 設定對應的屬性:
- name¶
嘗試引入 (import) 的模組名稱。
- path¶
觸發此例外的任何檔案的路徑。
- exception ModuleNotFoundError¶
ImportError的子類別,當模組不能被定位的時候會被import所引發。當在sys.modules裡找到None時也會被引發。在 3.6 版被加入.
- exception IndexError¶
當序列的索引超出範圍的時候會被引發。(切片索引 (slice indices) 會默默地被截短使其能落在允許的範圍內;如果索引不是整數,
TypeError會被引發。)
- exception KeyError¶
當對映(字典)的鍵無法在已存在的鍵的集合中被找到時會被引發。
- exception KeyboardInterrupt¶
當使用者輸入中斷鍵 (interrupt key)(一般來說是 Control-C 或 Delete)時會被引發。在執行過程中,會定期檢查是否產生中斷。此例外繼承自
BaseException以防止意外地被捕捉Exception的程式碼所捕捉,而因此讓直譯器無法結束。備註
捕捉
KeyboardInterrupt需要特殊的考量。因為它可以在無法預期的時間點被引發,可能在某些情況下讓正在跑的程式處在一個不一致的狀態。一般來說最好讓KeyboardInterrupt越快結束程式越好,或者完全避免引發它。(參考 訊號處理程式與例外的說明。)
- exception MemoryError¶
當一個操作用光了記憶體但情況還可能被修復 (rescued)(透過刪除一些物件)的時候被引發。關聯值是一個字串,表示什麼類型的(內部)操作用光了記憶體。需注意的是因為底層的記憶體管理架構(C 的
malloc()函式),直譯器可能無法總是完整地從該情況中修復;僅管如此,它還是引發例外以讓堆疊回溯可以被印出,以防原因出在失控的程式。
- exception NameError¶
當找不到本地或全域的名稱時會被引發。這只應用在不合格的名稱 (unqualified name) 上。關聯值是一個錯誤訊息,包含那個無法被找到的名稱。
可選的僅限關鍵字引數 name 設定對應的屬性:
- name¶
嘗試被存取的變數名稱。
在 3.10 版的變更: 新增
name屬性。
- exception NotImplementedError¶
此例外衍生自
RuntimeError。在使用者定義的基礎類別裡,當抽象方法要求衍生類別覆寫該方法時應該要引發此例外,或者當類別正在開發中,可用此例外表示還需要加入真正的實作。備註
此例外不應該用來表示根本沒有要支援的運算子或方法 ── 在這個情況下可以讓該運算子或方法保持未定義,或者如果是子類別的話將其設成
None。警示
NotImplementedError和NotImplemented並不是可互換的。這個例外只能用在上面描述的情況;參考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 版的變更:
EnvironmentError、IOError、WindowsError、socket.error、select.error及mmap.error已合併進OSError,而建構函式可能會回傳子類別。在 3.4 版的變更:
filename屬性現在是傳入函式的原始檔名,而不是從檔案系統編碼和錯誤處理函式編碼或解碼過的名稱。並且新增 filename2 建構函式引數與屬性。
- exception OverflowError¶
當運算操作的結果太大而無法表示的時候會引發此例外。這不會發生在整數上(會改成引發
MemoryError而不是放棄)。然而,因為一些歷史因素,OverflowError 有時候會因為整數在要求範圍之外而引發。因為在 C 裡面缺乏浮點數例外處理的標準化,大部分的浮點數運算都沒有被檢查。
- exception PythonFinalizationError¶
此例外衍生自
RuntimeError。當一個操作在直譯器關閉(也稱作 Python 最終化 (Python finalization))期間被阻塞會引發此例外。在 Python 最終化期間,能夠以
PythonFinalizationError被阻塞的操作範例:也可以參閱
sys.is_finalizing()函式。在 3.13 版被加入: 在之前,會引發一般的
RuntimeError。在 3.14 版的變更:
threading.Thread.join()現在可以引發此例外。
- 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__()方法引發,用來表示疊代器沒有更多項目可以產生。當 generator 或 coroutine 函式回傳時,新的
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_lineno與end_offset屬性。
- exception IndentationError¶
與不正確的縮排有關的語法錯誤的基礎類別。這是
SyntaxError的子類別。
- exception TabError¶
當縮排包含製表符號 (tab) 和空白的不一致用法時會引發此例外。這是
IndentationError的子類別。
- exception