1. 程式人生 > 其它 >Python 中的異常處理

Python 中的異常處理

1 異常處理

異常即是一個事件,該事件會在程式執行過程中發生,會讓程式崩潰,中止執行;為了防止程式中斷,增加程式的健壯性,可以做一些預處理,當Python指令碼發生異常時可以捕獲處理它。

1.1 常見異常

AttributeError 試圖訪問一個物件沒有的樹形,比如foo.x,但是foo沒有屬性x
IOError 輸入/輸出異常;基本上是無法開啟檔案
ImportError 無法引入模組或包;基本上是路徑問題或名稱錯誤
IndentationError 語法錯誤(的子類) ;程式碼沒有正確對齊
IndexError 下標索引超出序列邊界,比如當x只有三個元素,卻試圖訪問x[5]
KeyError 試圖訪問字典裡不存在的鍵
KeyboardInterrupt Ctrl
+C被按下 NameError 使用一個還未被賦予物件的變數 SyntaxError Python程式碼非法,程式碼不能編譯(個人認為這是語法錯誤,寫錯了) TypeError 傳入物件型別與要求的不符合 UnboundLocalError 試圖訪問一個還未被設定的區域性變數,基本上是由於另有一個同名的全域性變數, 導致你以為正在訪問它 ValueError 傳入一個呼叫者不期望的值,即使值的型別是正確的
  Python的異常處理能力是很強大的,它有很多內建異常,可向使用者準確反饋出錯資訊,在Python中,異常也是物件,可對它進行操作。BaseException是所有內建異常的基類,但使用者定義的類並不直接繼承BaseException,所有的異常類都是從Exception繼承,且都在exceptions模組中定義。Python自動將所有異常名稱放在內建名稱空間中,所以程式不必匯入exceptions模組即可使用異常。一旦引發並且沒有捕捉SystemExit異常,程式執行就會終止。

1.2 異常處理語法結構

try:
<語句>        #執行別的程式碼
except <異常名稱><語句>        #如果在try部份引發了'name'異常
except (<異常A>,<異常B>):
<語句>        #如果引發了'name'異常,獲得附加的資料
else:
<語句>        #如果沒有引發異常,則執行else中的語句
finally:   
<語句>    # 無論是否發生異常都將執行finally程式碼
raise

1.3 異常捕獲場景

如果我們已經知道這種型別的錯誤,那麼就可以通過一個異常來捕捉這個錯誤。我們可以通過try...except 來預知處理這個異常。
1.3.1 指定單個異常
只能用來處理指定的異常情況,如果未捕獲到異常,則報錯。
try:
    open("test.text")
except FileNotFoundError as e:  # as+變數名:重新命名異常資訊
    print("檔案操作失敗,原因:", e)
# 執行結果:
檔案操作失敗,原因: [Errno 2] No such file or directory: 'test.text'
1.3.2 捕獲多個異常
一般建議捕獲可能出現的多個異常(按照先子類後父類的順序),並且針對性的寫出多個異常處理程式碼。異常可以分別處理,或者放在一行處理。 方法一:多分支
def dev(a, b):
    try:
        c = float(a)/float(b)
    except ValueError as e:  # as+變數名:重新命名異常資訊
        print("字串不能做除法,具體異常如下:", e)
    except ZeroDivisionError as e:
        print("0不能作為除數,具體異常資訊:", e)
dev(2, 0)
異常處理規則: ①第一個except中定義的異常與引發的異常匹配,則執行該except中的語句; ②引發的異常不匹配第一個except,則會搜尋第二個except,允許編寫的except數量沒有限制 ③所有的except都不匹配,則異常未捕獲就會丟擲 方法二:一行except同時處理多個異常
def dev(a, b):
    try:
        c = float(a)/float(b)
    except (ValueError, ZeroDivisionError) as e:  # as+變數名:重新命名異常資訊
        print("具體異常如下:", e)
dev(2, 0)
1.3.3 萬能異常
在python的異常中,有一個萬能異常:Exception,它可以捕獲任意異常。它是一把雙刃劍,有利有弊,我們要視情況使用,優點是什麼異常都會被捕獲,但是會導致我們不清楚是哪種型別的異常資訊,因此可與多分支結合使用,需要注意的是,萬能異常一定要放在最後,否則就沒有意義了。
def dev(a, b):
    try:
        c = float(a)/float(b)
    except Exception as e:  # as+變數名:重新命名異常資訊
        print("具體異常如下:", e)
dev(2, 0)

1.3.4 異常中的else

如果判斷完沒有某些異常之後還想做其他事,就可以使用下面這樣的else語句,else下的語句是隻有無異常時才會執行,否則不執行。else和finally是可選的,可能會有0個或多個except,但是,如果出現一個else的話,必須有至少一個except。
def dev(a, b):
    try:
        c = float(a)/float(b)
    except Exception as e:  # as+變數名:重新命名異常資訊
        print("具體異常如下:", e)
    else:
        print("無異常")
dev(2, 0)

1.3.5 異常中的finally

try...finally...語句無論是否發生異常都將會執行最後的程式碼。
try:
     <語句>
finally:
    關閉瀏覽器
    driver.quit()
1.4 異常的其他用途
捕獲異常不僅是為了防止程式中斷,還可以通過異常進行場景處理,如以下程式碼,通過捕獲異常IndexError取代列表長度判斷,減少程式碼量。
# 題目:給你一個非空陣列,返回此陣列中第三大的數 。如果不存在,則返回陣列中最大的數。
def ThirdNum(num_list):
    if num_list:
        try:
            return sorted(list(set(num_list), reverse=False)[2]
        except IndexError:
            return sorted(num_list, reverse=True)[0]
    else:
        print("傳入陣列不能為空")
if __name__ == '__main__':
    alist = [2, 9]
    print(ThirdNum(alist))