Python中的異常處理

2021-09-22 12:31:54 字數 4442 閱讀 4827

12.2 捕獲異常

12.3 手動丟擲異常

13.4. 自定義異常

在程式設計過程中,會出現各種「問題」,「問題」大致分為兩種:

異常是程式執行過程中產生的一種事件,該事件會打亂程式的正常流程。可以說,異常就是一種意外,指程式沒有按照正常或期望的方式執行

當異常產生時,會建立乙個相關異常類的物件,該物件含有異常的相關資訊。異常產生時,會在異常的上下文中尋找異常處理程式,如果沒有異常處理程式,則異常產生之後的語句將不會得到執行。該異常會向上傳播。傳播的方式為:

異常命名慣例,以error結尾。

baseexception

exception

1. zerodivisionerror

2. nameerror

3. typeerror

4. atrributeerror

5. indentation

6. indexerror

7. unboundlocalerror

8. assertionerror

9. modulenotfounderror

10. keyerror

11. recursionerror

12. stopiteration

13. valueerror

14. syntaxerror

在python中,可以使用try-except的語法來捕獲異常,我們可以將其稱為異常處理程式。其語法格式如下:

try

: 可能產生異常的程式

except 異常型別1:

恢復措施

except 異常型別2:

恢復措施

……except 異常型別n:

恢復措施

其中,try用來執行可能會產生異常的程式,而except用來捕獲try中產生的異常,用來執行一些恢復或補救操作,或者給出錯誤的提示資訊等。這分為三種情況:

獲取異常物件

我們可以使用except捕獲異常,同時,我們也能夠使用as語法獲取try中產生的異常物件。語法格式為:

try

: 可能產生異常的**

except 異常型別 as 變數:

處理異常**

當異常匹配成功時,我們就會將try中產生的異常物件賦值給as變數名,然後,我們就可以在except中使用變數名來訪問異常物件了。

try

:print(5

/0)except zerodivisionerror as e:

# 通過異常物件的args屬性獲取異常物件構造器的引數。

print

(e.args)

異常物件的args屬性返回乙個元組型別,其中存放異常物件建立時,傳遞給構造器中的引數值。

因為在try語句塊中,可能產生不止一種異常,故我們會使用多個except分支來捕獲這些可能產生的異常。如果多個異常類之間沒有繼承關係時,except分支的順序不是十分重要,但是,當異常類之間存在異常關係時,就一定要將子類放在前面,父類放在後面。因為子類異常物件也是父類異常類的例項,如果將父類分支放在子類分支之前,則就算try中產生子類異常,也會先由父類分支率先捕獲,子類分支永遠都沒有機會執行,這就失去了意義。

所以,在捕獲異常時,except分支應該按照從特殊性(子類)到一般性(父類)的方式排序。

except還有一種語法,就是不指定異常型別,此時表示捕獲所有異常型別。例如:

try

: 可能產生異常的**

except

:# 沒有指定異常型別,會捕獲所有的異常。

pass

因為捕獲所有的異常型別是最廣泛的(最具有一般性),所以,如果使用這種方式,則必須將該except置於最後(作為最後一條except分支)。

同時捕獲多個異常

當try中產生了兩種(或更多)的異常,而多種異常的處理方式又完全相同時,我們使用多條except分支,會造成**的重複。

此時,我們可以使用一條except分支,同時捕獲多個異常來代替。

try

:# 操作

except

(indexerror, keyerror)

:print

("提供值不合法,獲取失敗!"

)

這樣,無論try中產生indexerror還是keyerror,except分支都可以進行捕獲。

也許大家會有這樣的想法,這種捕獲多個異常有什麼用呢,使用不指定異常型別的except豈不是更好,能捕獲所有異常,可謂「萬事通用」。

try

:# 操作

except

:print

("提供值不合法,獲取失敗!"

)

但是,如果這樣做,就很可能會捕獲預期之外的異常,從而掩埋真正的問題,令錯誤不易排查。因此,如果能夠捕獲更加具體明確的異常型別,我們最好不要使用更加通用一般的異常型別代替。

try-except還可以跟隨可選的else語句。語法為:

try

: ……

except 異常型別:

……else

: ……

當try中沒有產生異常時,就會執行else分支,否則,不執行else分支。

try-except還可以帶上乙個可選的finally。如果同時存在else,則finally必須處於else的後面,其實,except,else,與finally都是可選的。但是,except與finally二者不能同時缺失,即二者至少要存在乙個。

finally會在try-except-else之後得到執行(如果存在except或else的話),且一定會得到執行。即無論try是否產生異常,也無論except是否捕獲try中產生的異常,finally終將會得到執行。考慮到finally總是可以執行的特徵,我們往往會在finally中執行一些清理的工作。例如,我們在try中申請了一些系統資源(檔案讀寫,資料庫連線等),就可以在finally中進行資源釋放,從而不會造成資源洩露(資源申請,但沒有釋放)。如果將釋放語句寫在try中,則一旦在釋放之前產生異常,則資源釋放語句就不會得到執行。

finally總是會執行的嘗試。當try語句體中嘗試返回乙個變數時,如果在finally中去修改該變數的值,不會影響到返回值的結果(返回的還是修改之前的值)。

我們也可以自行建立乙個異常型別的物件,然後將其丟擲。這與之前產生異常的行為是相同的。也許大家為問:異常是一種意外,是我們應該極力去避免的,為什麼還要主動去「建立」異常呢?

我們在編寫程式時,可能會接收呼叫端傳遞過來的值,但是,我們無法保證呼叫端傳遞的值永遠是正確的。例如,在註冊使用者的時候,提供年齡資訊,如果輸入了負值,這明顯是不正確的。我們可以使用if來進行判斷:

def

register

(age)

:if age >0:

註冊操作

我們進行了合理的判斷,但問題是,如果age小於等於0,則程式會「保持沉默」,沒有任何資訊提示。這對於呼叫端來說,可能未必是一件好事。如果這個行為很重要,那此時產生乙個異常才是更合理的結果。因為使用if判斷的形式,縱然呼叫端傳遞非法的值,我們最多也只是不執行操作,但卻沒有什麼有效的措施能夠牽制呼叫端,或是以一種強力的方式去通知呼叫端已經犯了較為嚴重的錯誤。儘管,我們可以使用print函式列印提示資訊,但呼叫端很可能會忽略這些資訊。

相反,丟擲異常的方式則不同。異常可以向上傳播,如果呼叫端沒有明確對異常進行處理,將會導致當前的執行緒終止,同時顯示異常的錯誤資訊,這就可以引起呼叫端足夠的重視,而不至於掩蓋程式的bug(軟體漏洞)。

我們可以建立乙個異常物件,使用raise丟擲,語法為:

raise 異常類或異常物件

例如:

raise exception(

"產生異常"

)raise exception

raise後面跟隨異常類,則相當於是呼叫其無參的構造器,因此,後者相當於:

raise exception(

)

raise後面必須是乙個有效的異常類(baseexception型別或其子型別)或對應異常類的物件,如果是其他型別,將會產生錯誤。

這裡還有乙個問題,既然呼叫端可以採用try-except處理異常,那為什麼不在register方法裡面捕獲可能的異常呢?這樣不就方便所有的呼叫端了嗎?原因如下:

之前,我們使用的是內建的異常型別valueerror,但是,valueerror是python內建的異常型別,其具有自身特殊的應用場景,如果我們使用系統內建的異常型別,容易造成混淆。例如,我們在年齡不合法時丟擲該異常,而數值轉換失敗時,移位運算右側運算元為負數時也會產生該異常,這就不便於我們定位與排查問題。因此,我們可以自定義異常型別,用在我們需要的場景,這樣就可以避免與內建異常型別相互干擾。

python 中的異常處理

python的異常處理能力是很強大的,可向使用者準確反饋出錯資訊。在python中,異常也是物件,可對它進行操作。所有異常都是基類exception的成員。所有異常都從基類exception繼承,而且都在exceptions模組中定義。python自動將所有異常名稱放在內建命名空間中,所以程式不必匯...

Python中的異常處理

當python檢測到乙個錯誤時,直譯器就無法繼續執行了,反而出現了一些錯誤的提示,這就是所謂的 異常 看如下示例 try print test1 open 123.txt r print test2 except ioerror pass此時可以正常執行,執行結果為 test1 說明 try exc...

python中的異常處理

python使用異常物件來表示異常狀態,並在遇到錯誤時引發異常,異常物件未被處理時,程式將終止並顯示一條錯誤資訊。raise語句 自定義異常類 class somecustomexception exception pass class myexceptionclass exception def ...