給妹子講python--24異常處理方式
陪伴學習,一路成長。請一起關注,一起點贊吧!
【要點搶先看】
1.try、except、else、finally、raise關鍵字2.異常的處理流程3.try/except/else/finally組成的幾種異常處理模式
通過上一節我們知道了python異常的整個框架。本節會詳細介紹異常編碼的語法模式,try/except/else和try/finally。
先重新回顧一下try、except、else、finally幾個關鍵字:
try後面緊跟著縮進的語句代碼,代表此語句的主要動作:試著執行的程序代碼。
然後是一個或多個except分句來識別要捕獲的異常,except子句內定義try代碼塊內引發的異常處理器,
最後是一個可選的else分句,提供沒發生異常時要執行的語句。
分別討論下面的幾種情形:
如果try代碼塊語句執行時的確發生了異常,python就跳出try,執行第一個符合引發異常的except子句下面的語句。當except代碼塊執行結束後,控制權就會到整個try代碼塊後繼續執行。
如果異常發生在try代碼塊內,沒有符合的except子句,異常就會傳遞到頂層,迫使python終止這個程序並列印默認的出錯信息。
如果try首行底下執行的語句沒有發生異常,python就會執行else行下的語句,控制權會在整個try語句下繼續。
換句話說,except分句會捕獲try代碼塊執行時所發生的異常,而else子句只在try代碼塊執行時不發生異常才會執行。
except是專註於異常處理器的:捕捉只在相關try代碼塊中的語句所發生的異常。儘管這樣,因為try代碼塊語句可以調用寫在程序其他地方的函數,異常的來源可能在try語句自身之外。
關於except子句的一些說明:
except子句可以用括弧列出一組異常[except (e1,e2,e3)],而如果except子句後沒有列出異常名稱,即except:時,會捕捉所有的異常類型。
但是,空except也會引發一些設計的問題,儘管方便,也可能捕捉和程序代碼無關、意料之外的系統異常,而且可能意外攔截其他處理器的異常。例如,在python中,即使是系統離開調用,也會觸發異常,而顯然你通常會想讓這些事件通過。
python引入了一個替代方案來解決這個問題,捕獲一個名為Exception的異常,幾乎與一個空的except:具有相同的效果,但是忽略和系統退出相關的異常。
來看看try/else語句的作用
也許我們無法一眼看出else子句的用途,不過仔細想想,如果沒有else,是無法知道控制流程是否通過了try語句,到底是沒有異常引發,還是異常發生了且已被處理過了,不使用else的話很難分得清。
再來分析一下try/finally語句
try中包含了finally子句,python一定會在try語句後執行其語句代碼塊,無論try代碼塊執行時是否發生異常。
利用這個變體,python可先執行try首行下的語句代碼塊。接下來發生的事情,取決於代碼塊中是否發生異常:
如果try代碼塊運行時沒有異常發生,python會跳至執行finally代碼塊,然後在整個try語句後繼續執行下去。
如果try代碼塊運行時有異常發生,python依然會回來運行finally代碼塊,但是接著會把異常向上傳遞到較高的try語句或頂層的默認異常處理器,程序不會在try語句下繼續執行。也就是說,即使發生了異常,finally代碼塊還是會執行的,和except不同的是,finally不會終止異常,而是在finally代碼塊執行後,拋出異常。
當想確定某些程序代碼執行後,無論程序的異常行為如何,有個動作一定會發生,那麼,try/finally形式就很有用。在實際應用中,這可以讓你定義一定會發生的清理動作,最直觀的就是,在出現異常時,仍能利用finally關閉文件和斷開伺服器連接。
最後我們來看最完整的形式:try/except/else/finally
try: main-actionexcept Exception1: handler1except Exception2: handler2...else: else-blockfinally: finally-block
我們從頭梳理一遍:
就像往常一樣,這個語句中的main-action代碼會先執行。如果該程序代碼引發異常,那麼所有except代碼塊就會逐一測試,尋找與拋出的異常相符的語句,如果引發的異常是Exception1,就會執行handler1,如果引發的的異常是Exception2,就會執行handler2,以此類推,如果沒有引發任何異常,將會執行else-block。而無論之前發生了什麼,當main-action代碼塊完成的時候,而任何引發的異常都已經處理後,finally-block就會執行。事實上,即使異常處理器或者else-block內有錯誤發生而引發新的異常,finally-block內的程序代碼依然會執行。就像之前所說的那樣,finally子句並沒有終止異常:當finally-block執行的時候,如果異常還存在,就會在finally-block代碼塊執行後繼續傳遞,而控制權會跳至程序其他地方,如我們的默認的頂層處理器。
最後我們叮囑一下,try語句必須有一個except或一個finally,else是可選的,但是如果有else,則必須至少有一個except。
最後我們簡單的再說說raise
要顯式的觸發異常,可使用raise語句,其一般形式相當簡單。raise語句的組成是:raise+可選的要引發的類或者類的一個實例。
如果傳遞的是一個類,其實python會調用不帶構造函數參數的類,以創建被引發的一個實例;這個格式等同於在類後面添加圓括弧。本質上仍然是傳遞了一個對象。
我們看一個例子:對於之前我們經常看到的IndexError,下面兩種形式是對等的,
raise IndexErrorraise IndexError()
都會引髮指定異常類的一個實例,其中第一種形式隱式的創建實例。
當使用下列的語法形式的時候
try: passexcept IndexError as e: print(e.args)
實質是把捕捉到的異常對象賦予了e這個變數名,這樣可以方便的訪問異常實例的數據以及異常類中的方法。
推薦閱讀: