1. 程式人生 > 其它 >【python教程】4、定義、引發建立、捕獲異常

【python教程】4、定義、引發建立、捕獲異常

1、什麼是異常

python使用異常物件來表示異常狀態,並在遇到錯誤時引發異常。異常物件未被處理或捕獲時,程式將終止並顯示一條錯誤訊息(traceback)。如下:

>>> 1/0
Traceback(most recent call last):
 File"<stdin>", line 1, in?
ZeroDivisionError.integer division or modulo by zero

每個異常都是某個類(如ZeroDivisionError)的例項,我們可以以各種方式引發和捕獲這些例項,從而逮住錯誤並採取措施,而不是放任整個程式失敗。

2、引發和建立異常

raise語句引發異常:將一個類(必須是Exception的子類)或例項作為引數。

raise Exception  # 將類作為引數時,將自動建立一個例項。這裡引發的是通用異常,沒有指出出現了什麼錯誤。
raise Exception('hyperdrive overload')  # 添加了錯誤訊息hyperdrive overload

比較重要的一些內建的異常類:

Exception:幾乎所有的異常類都是從它派生而來的
AttributeError:引用屬性或給他賦值失敗時引發
OSError:作業系統不能執行指定的任務(如開啟檔案)時引發,有多個子類
indexError:使用序列中不存在的索引時引發,為LookupError的子類
KeyError:使用對映中不存在的鍵時引發,為LookupError的子類
NameError:找不到名稱(或變數)時引發
SyntaxError:程式碼不正確時引發
TypeError:將內建操作或函式用於型別不正確的物件時引發
ValueError:將內建操作或函式用於這樣的物件時引發:其型別正確但包含的值不合適
ZeroDivisionError:在除法或求模運算的第二個引數為0時引發

3、捕獲異常

異常有趣的地方是可對其進行處理,稱之為捕獲異常。常用:try/except語句。基本用法:

# 一:捕獲異常並對錯誤進行處理(列印友好的錯誤訊息)
try:
    x = int(input('first number:'))
    y = int(input('second number:'))
    print(x / y)
except ZeroDivisionError:
    print("the second number can't be zero!")
	
# 二:捕獲異常後,抑制異常
class MuffledCalculator:
    muffled = False
    def calc(self, expr):
        try:
            return eval(expr)
	except ZeroDivisionError:
	    if self.muffled:  # 與使用者互動時,啟用抑制功能,不讓異常繼續傳播
		print('Division by zero is illegal')
	    else:  # 在程式內部使用時,關閉抑制功能,引發異常
		raise
# 注意:發生除零行為,若啟用抑制功,calc將隱式地返回None。

# 三:在except子句中,引發別的異常
try:
    1 / 0
except ZeroDivisionError:
    raise ValueError  # 進行except子句的異常將被作為異常上下文儲存起來,並出現在最終的錯誤訊息中

# 四:使用None來禁用上下文
try:
    1 / 0
except ZeroDivisionError:
    raise ValueError from None

# 執行結果如下:
Traceback(most recent call last):
    File"<stdin>", line 3, in <module>
ValueError

其他用法:

# 一、多個except子句,捕獲多種異常
try:
    x = int(input('first number:'))
    y = int(input('second number:'))
    print(x / y)
except ZeroDivisionError:
    print("the second number can't be zero!")
except TypeError:
    print("That wasn't a number, was it")
	
# 二、一個except子句捕獲多個異常,可在元組中指定異常(一個引數)
try:
    x = int(input('first number:'))
    y = int(input('second number:'))
    print(x / y)
except (ZeroDivisionError, TypeError, NameError):
    print("your numbers were bogus ...")

# 三、捕獲異常物件本身(可使用兩個引數)
try:
    x = int(input('first number:'))
    y = int(input('second number:'))
    print(x / y)
except (ZeroDivisionError, TypeError) as e:
    print(e)  # 列印異常並繼續執行
	
# 四、捕獲所有異常,在except中不指定任何異常類即可
try:
    x = int(input('first number:'))
    y = int(input('second number:'))
    print(x / y)
except:
    print('something wrong happened ...')
# 這種做法很危險,會捕獲到使用者使用ctrl+c或呼叫函式sys.exit來終止執行的企圖等。推薦使用except Exception as e對異常物件進行檢查。(可能會讓不是從Exception派生而來的異常漏網,如SystemExit、KeyboardInterrupt,他們是從Exception的超類BaseException派生而來)

# 五、給try/except新增else子句和finally:沒有出現異常時會執行else中程式碼塊
x = None
try:
    x = 1 / 0
except NameError:
    print('unknown variable')
else:
    print("that went well!")
finally:
    print("cleaning up...")
    del x  # 發生異常時,執行finally子句清理工作(適用於確保檔案或網路套接字等得以關閉)

4、異常之禪

很多情況下,相比使用if/else,使用try/except語句更自然,也更符合python風格。(直接去做,有問題在處理,而不是預先做大量的檢查)