Python進階|聊聊異常處理

  • 2019 年 10 月 7 日
  • 筆記
前言

在編寫代碼中,總會遇到一些bug和報錯,怎麼去捕獲這些異常,並進行處理,以讓程序更健碩了?本篇文章將帶你聊聊Python的異常處理。

錯誤與異常

編寫的程序出錯,至少有兩種可能,一是語法錯誤,二就是我們說的異常。

語法錯誤很好理解,就是我們寫的代碼不符合Python代碼的規範,導致程序無法識別和運行,比如下面這個例子:

def add(a,b)      print(a+b)    add(1,2)    #SyntaxError: invalid syntax

我們定義函數漏掉了冒號,所以導致出錯,報錯為SyntaxError。

而異常是指本身的程序編寫沒有錯誤,在執行中出現了問題,拋出了異常,比如我們都知道0不能作為分母,那我們把0當為分母,就會拋出異常ZeroDivisionErro。

1/0    # ZeroDivisionError: division by zero

我們在看看其他的異常類型:

1 + 'a'  # TypeError: unsupported operand type(s) for +: 'int' and 'str'    print(name)  #NameError: name 'name' is not defined

當然Python還有很多其他的異常類型,可以參考Python的官方文檔進行查看(https://docs.python.org/3/library/exceptions.html#bltin-exceptions

處理異常

我們都知道,拋出異常後,整個程序就會被終止,當然理想情況下,我們是希望程序不被終止,而是捕捉到這次異常。

當然Python有這樣的語法來實現並處理異常,這就是try和except來解決。

try:      嘗試運行程序      出現異常後這段代碼就不會運行  except 錯誤類 as e:      發生異常運行這部分代碼

我們就拿0不能作為分母來進行演示:

try:      a = 1/0      print(a)  except ZeroDivisionError as e:      print("錯誤:{}".format(e))    #錯誤:division by zero

這裡我們需要注意的是,如果程序的異常與except中定義的異常不匹配時,程序還是會報錯,例如:

try:      print(name)  except ZeroDivisionError as e:      print("錯誤:{}".format(e))  # NameError: name 'name' is not defined

所以,當我們有多個異常錯誤時,這種寫法就有局限性,我們可以這樣來寫:

#第一種方法  try:      print(1/0)      print(name)  except (ZeroDivisionError,NameError) as e:      print("錯誤:{}".format(e))    #第二種方法  try:      print(1/0)      print(name)  except ZeroDivisionError as e:      print("錯誤:{}".format(e))  except NameError as e:      print("錯誤:{}".format(e))    # 錯誤:division by zero

細心的讀者可能會發現,我們程序運行的結果是表示捕捉到了0不能為分母的錯誤,那NameError為什麼沒有被捕捉到了?

那是因為程序存在多個except異常時,程序最多只有一個會被執行並捕捉,簡單的說,最先捕捉的異常會被執行,其他都會被忽略。

那有時候我們事先並不知道有多少異常,應該怎麼處理了?我們可以用Exception,他是其他非系統異常的基類。或者在except語句塊後面不加異常類。

try:      print(1/0)      print(name)  except Exception as e:      print("錯誤:{}".format(e))    try:      print(1/0)      print(name)  except:      print("錯誤")

最後,我們看看finally,其作用是不管有無異常,finally內的語句都會被執行。

try:      f = open('test.txt','r')  except:      print('erro')  finally:      f.close()

這裡讀取文件,不管是否出現異常,都會執行關閉文件的操作。

主動拋出異常

我們可以通過raise語句主動拋出異常,其用法為:raise 後跟要拋出的異常。這個異常必須是異常實例或者是一個異常類。

那我們通過raise玩個好玩的事情,0不能為分母的異常提示是英文的,我自己主動拋出個異常,換為中文提示。

try:      raise ZeroDivisionError('分母不能為零!!')  except ZeroDivisionError as e:      print('錯誤:{}'.format(e))    # 錯誤:分母不能為零!!
自定義異常類

如果Python內置的異常類型不滿足我們的需求時,我們可以自定義異常類。但我們需要注意的是,所有內置的非系統退出類異常都派生Exception類, 所有用戶自定義異常也應當派生自此類。

簡單的說,我們自己寫的異常類必須直接或間接集成Exception類。

例如:

class MyError(Exception):      def __init__(self,value):          self.value = value      def __str__(self):          return '{} is error'.format(repr(self.value))    try:      raise MyError(1)  except MyError as e:      print(e)    # 1 is error

兩個魔法方法: def init(self),異常類對象的初始化屬性; def str(self),返回異常類對象說明信息。

總結
  • 錯誤與異常
  • 異常處理
  • 拋出異常
  • 自定義異常