異常即是一個事件,該事件會在程序執行過程中發生,影響了程序的正常執行。一般情況下,在Python無法正常處理程序時就會發生一個異常。異常是Python對象,表示一個錯誤。當Python腳本發生異常時我們需要捕獲處理它,否則程序會終止執行。
當一個未捕獲的異常發生時,Python將結束程序並列印一個堆棧跟蹤信息,以及異常名和附加信息。具體如下:
Traceback (most recent call last): File "<pyshell#1>", line 1, in <module>ZeroDivisionError: division by zero廣義上的錯誤分為錯誤和異常
錯誤通常指的是語法錯誤,可以人為避免
異常是指在語法邏輯正確的而前提下,出現的問題
在Python中捕獲和處理異常的主要目的:
錯誤處理:在運行時出現錯誤的情況下,應用程式可能會無條件終止。使用異常處理,我們可以處理失敗的情況並避免程序終止。
代碼分離:錯誤處理可以幫助我們將錯誤處理所需的代碼與主邏輯分離。與錯誤相關的代碼可以放置在「 except 」塊中,該塊將其與包含應用程式邏輯的常規代碼隔離開來。
錯誤區分:幫助我們隔離執行過程中遇到的不同類型的錯誤。我們可以有多個「 except」塊,每個塊處理一種特定類型的錯誤。
其他方面的應用:
事件通知:異常也可以作為某種條件的信號,而不需要在程序裡傳送結果標誌或顯式地測試它們。
特殊情形處理:有時有些情況是很少發生的,把相應的處理代碼改為異常處理會更好一些。
特殊的控制流:異常是一個高層次的」goto」,可以把它作為實現特殊控制流的基礎。如反向跟蹤等。
Python自帶的異常處理機制非常強大,提供了很多內置異常類,可向用戶準確反饋出錯信息。Python是面向對象語言,認為一切皆對象,所以異常也是對象。Python異常處理機制中的BaseException是所有內置異常的基類,但用戶定義的類並不直接繼承BaseException,所有的異常類都是從Exception繼承,且都在exceptions模塊中定義。Python自動將所有異常名稱放在內建命名空間中,所以程序不必導入exceptions模塊即可使用異常。
Python內置異常類繼承層次結構如下:
-- SystemExit # 解釋器請求退出-- KeyboardInterrupt # 用戶中斷執行(通常是輸入^C)-- GeneratorExit # 生成器(generator)發生異常來通知退出 -- StopIteration # 迭代器沒有更多的值 -- StopAsyncIteration # 必須通過異步迭代器對象的__anext__()方法引發以停止迭代 -- ArithmeticError # 各種算術錯誤引發的內置異常的基類 | -- FloatingPointError # 浮點計算錯誤 | -- OverflowError # 數值運算結果太大無法表示 | -- ZeroDivisionError # 除(或取模)零 (所有數據類型) -- AssertionError # 當assert語句失敗時引發 -- AttributeError # 屬性引用或賦值失敗 -- BufferError # 無法執行與緩衝區相關的操作時引發 -- EOFError # 當input()函數在沒有讀取任何數據的情況下達到文件結束條件(EOF)時引發 -- ImportError # 導入模塊/對象失敗 | -- ModuleNotFoundError # 無法找到模塊或在在sys.modules中找到None -- LookupError # 映射或序列上使用的鍵或索引無效時引發的異常的基類 | -- IndexError # 序列中沒有此索引(index) | -- KeyError # 映射中沒有這個鍵 -- MemoryError # 內存溢出錯誤(對於Python 解釋器不是致命的) -- NameError # 未聲明/初始化對象 (沒有屬性) | -- UnboundLocalError # 訪問未初始化的本地變量 -- OSError # 作業系統錯誤,EnvironmentError,IOError,WindowsError,socket.error,select.error和mmap.error已合併到OSError中,構造函數可能返回子類 | -- BlockingIOError # 操作將阻塞對象(e.g. socket)設置為非阻塞操作 | -- ChildProcessError # 在子進程上的操作失敗 | -- ConnectionError # 與連接相關的異常的基類 | | -- BrokenPipeError # 另一端關閉時嘗試寫入管道或試圖在已關閉寫入的套接字上寫入 | | -- ConnectionAbortedError # 連接嘗試被對等方中止 | | -- ConnectionRefusedError # 連接嘗試被對等方拒絕 | | -- ConnectionResetError # 連接由對等方重置 | -- FileExistsError # 創建已存在的文件或目錄 | -- FileNotFoundError # 請求不存在的文件或目錄 | -- InterruptedError # 系統調用被輸入信號中斷 | -- IsADirectoryError # 在目錄上請求文件操作(例如 os.remove()) | -- NotADirectoryError # 在不是目錄的事物上請求目錄操作(例如 os.listdir()) | -- PermissionError # 嘗試在沒有足夠訪問權限的情況下運行操作 | -- ProcessLookupError # 給定進程不存在 | -- TimeoutError # 系統函數在系統級別超時 -- ReferenceError # weakref.proxy()函數創建的弱引用試圖訪問已經垃圾回收了的對象 -- RuntimeError # 在檢測到不屬於任何其他類別的錯誤時觸發 | -- NotImplementedError # 在用戶定義的基類中,抽象方法要求派生類重寫該方法或者正在開發的類指示仍然需要添加實際實現 | -- RecursionError # 解釋器檢測到超出最大遞歸深度 -- SyntaxError # Python 語法錯誤 | -- IndentationError # 縮進錯誤 | -- TabError # Tab和空格混用 -- SystemError # 解釋器發現內部錯誤 -- TypeError # 操作或函數應用於不適當類型的對象 -- ValueError # 操作或函數接收到具有正確類型但值不合適的參數 | -- UnicodeError # 發生與Unicode相關的編碼或解碼錯誤 | -- UnicodeDecodeError # Unicode解碼錯誤 | -- UnicodeEncodeError # Unicode編碼錯誤 | -- UnicodeTranslateError # Unicode轉碼錯誤 -- Warning # 警告的基類 -- DeprecationWarning # 有關已棄用功能的警告的基類 -- PendingDeprecationWarning # 有關不推薦使用功能的警告的基類 -- RuntimeWarning # 有關可疑的運行時行為的警告的基類 -- SyntaxWarning # 關於可疑語法警告的基類 -- UserWarning # 用戶代碼生成警告的基類 -- FutureWarning # 有關已棄用功能的警告的基類 -- ImportWarning # 關於模塊導入時可能出錯的警告的基類 -- UnicodeWarning # 與Unicode相關的警告的基類 -- BytesWarning # 與bytes和bytearray相關的警告的基類 -- ResourceWarning # 與資源使用相關的警告的基類。被默認警告過濾器忽略。異常捕獲與處理我們不能保證編寫的程序永遠正確運行,異常捕獲與處理的宗旨是保證程序在最壞的情況下得到的問題被妥善管理。
try:
可能產生異常的代碼塊
except [ (Error1, Error2, ... ) [as e] ]:
處理異常的代碼塊1
except [ (Error3, Error4, ... ) [as e] ]:
處理異常的代碼塊2
except [Exception]:
處理其它異常
else:
沒有異常時執行的代碼塊
finally:
不管有沒有異常都會執行的代碼塊try: 可能產生異常的代碼塊except [ (Error1, Error2, ... ) [as e] ]: 處理異常的代碼塊1except [ (Error3, Error4, ... ) [as e] ]: 處理異常的代碼塊2except [Exception]: 處理其它異常else: 沒有異常時執行的代碼塊finally: 不管有沒有異常都會執行的代碼塊try的工作原理是,當開始一個try語句後,python就在當前程序的上下文中作標記,這樣當異常出現時就可以回到這裡,try子句先執行,接下來會發生什麼依賴於執行時是否出現異常。
如果當try後的語句執行時發生異常,Python就跳回到try並執行第一個匹配該異常的except子句,異常處理完畢,控制流就通過整個try語句(除非在處理異常時又引發新的異常)。如果在try後的語句裡發生了異常,卻沒有匹配的except子句,異常將被遞交到上層的try,或者到程序的最上層(這樣將結束程序,並列印預設的出錯信息)。如果在try子句執行時沒有發生異常,Python將執行else語句後的語句(如果有else的話),然後控制流通過整個try語句。
代碼實例:
try: file_reader = open("a.json") print(file_reader.read())except FileNotFoundError: print("The File Cannot be Found")except: print("This is the Generic Error")finally: print("Closing File Reader...") file_reader.close()Exception類是所有Python異常類的父類,所以except Exception將可以捕獲任何異常,換句話說,它是萬能異常處理句式。有一種錯誤沒辦法抓住:縮進錯誤。
raise:手動引發異常有時候,異常可以作為代碼運行的標誌,通過主動觸發異常可以改變代碼的運行路線,從而提高代碼健壯性。
主動觸發異常需使用raise關鍵字,其語法結構如下:
raise [Exception [, args [, traceback]]]示例:
try: a = int(input("Enter a positive integer value: ")) if a <= 0: raise ValueError("This is not a positive number!!")except ValueError as ve: print(ve)語句中Exception是異常的類型(例如,ValueError)參數是一個異常參數值。該參數是可選的,如果不提供,異常的參數是」None」。最後一個參數是可選的(在實踐中很少使用),如果存在,是跟蹤異常對象。
自定義異常你可以通過創建一個新的異常類來擁有自己的異常。異常類繼承自 Exception 類,可以直接繼承,或者間接繼承,例如:
class MyError(Exception): def __init__(self, value): self.value = value return repr(self.value) print('My exception occurred, value:', e.value)斷言:assert條件Python assert(斷言)用於判斷一個表達式,在表達式條件為 false 的時候觸發異常。斷言可以在條件不滿足程序運行的情況下直接返回錯誤,而不必等待程序運行後出現崩潰的情況,例如我們的代碼只能在 Linux 系統下運行,可以先判斷當前系統是否符合條件。
語法格式如下:
等價於:
if not expression: raise AssertionError(arguments)實例:
import sysassert ('linux' in sys.platform), "該代碼只能在 Linux 下執行"assert看上去不錯,然而用起來並不爽。就比如有人告訴你程序錯了,但是不告訴哪裡錯了。很多時候這樣的assert還不如不寫。常見方案是使用測試框架或其他包代替:py.test、unittest、ptest、assertpy…
traceback 獲取詳細的異常信息try…except…的輸出結果只能讓你知道報了這個錯誤,卻不知道在哪個文件哪個函數哪一行報的錯。使用 traceback 模塊可以非常清楚的了解具體錯誤內容在哪:
import traceback
try: 1 / 0except Exception as e: traceback.print_exc()輸出:
Traceback (most recent call last):File "test_traceback.py", line 3, in <module>1/0ZeroDivisionError: integer division or modulo by zeroPython程序的traceback信息均來源於一個叫做traceback object的對象,而這個traceback object通常是通過函數sys.exc_info()來獲取的:
import sys
def func1(): raise Exception("--func1 exception--")
def test1(): try: func1() except Exception as e: print(e)
def test2(): try: func1() except Exception as e: exc_type, exc_value, exc_traceback_obj = sys.exc_info() print("exc_type: %s" % exc_type) print("exc_value: %s" % exc_value) print("exc_traceback_obj: %s" % exc_traceback_obj)
if __name__ == '__main__': test1() test2()輸出結果:
--func1 exception--exc_type: <class 'Exception'>exc_value: --func1 exception--exc_traceback_obj: <traceback object at 0x0000024D2F6A22C8>
Process finished with exit code 0通過以上示例我們可以看出,sys.exc_info()獲取了當前處理的exception的相關信息,並返回一個元組,元組的第一個數據是異常的類型,第二個返回值是異常的value值,第三個就是我們要的traceback object.
有了traceback object我們就可以通過traceback module來列印和格式化traceback的相關信息。
參考連結:
錯誤和異常
traceback — 列印或檢索堆棧回溯