第九天
今天我們來說下Python中的異常,以及如何去處理異常。我們在程序編碼中難免會碰到異常夺巩,今天我們就要來簡要說明什么是異常货葬,如何處理異常。
1劲够、異常的定義
不論是Python語言震桶、Java語言以及其他任何語言,程序在執(zhí)行的過程中難免會產(chǎn)生的錯誤征绎,這些錯誤都可以稱之為異常蹲姐。比如列表索引越界、打開不存在的文件等人柿。
就如同下面兩行代碼:
print(str1)
# name 'str1' is not defined
open('error.txt','r')
# No such file or directory: 'error.txt'
2柴墩、異常處理
程序中出現(xiàn)異常是難免的,發(fā)生異常時我們需要捕獲處理它凫岖,否則程序會終止執(zhí)行江咳。
如下代碼:
#控制臺輸入兩個數(shù)字 求商
print('程序開始')
num1 = int(input('請輸入除數(shù)'))
num2 = int(input('請輸入被除數(shù)'))
print(str(num1)+'除以'+str(num2)+'的結(jié)果是',str(num1/num2))
print('程序結(jié)束')
上述這段代碼其實就是存在問題的,比如我在獲得數(shù)字num1的時候輸入的內(nèi)容不可以轉(zhuǎn)換為int(比如你輸入wasd),這個時候就出現(xiàn)異常了哥放。
ValueError: invalid literal for int() with base 10: 'wasd'
其實就是將非數(shù)字字符串轉(zhuǎn)換為整型出現(xiàn)的異常歼指;
如果你在獲得num2的時候,如果輸入了0也會出現(xiàn)異常甥雕,
ZeroDivisionError: division by zero
其實就是除以0的原因?qū)е碌摹?br>
并且我們發(fā)現(xiàn)上述兩種異常任何一種異常出現(xiàn)踩身,我們的程序就停止了,并且程序沒有往下執(zhí)行社露,因為我們在控制臺看不到最后一行print的輸出挟阻。
這時候就需要我們異常處理了。
2.1峭弟、異常類
在Python中附鸽,所有異常都是基類Exception的成員,它們都定義在exceptions模塊中瞒瘸。
如果這個異常對象沒有進(jìn)行處理和捕捉坷备,程序就會用所謂的回溯(traceback,一種錯誤信息)終止執(zhí)行挨务,這些信息包括錯誤的名稱(例如NameError)击你、原因和錯誤發(fā)生的行號。下面簡單說下我們經(jīng)常遇見的幾個異常:
1谎柄、NameError
嘗試訪問一個未聲明的變量丁侄,會引發(fā)NameError。
print(str1)
# NameError: name 'str1' is not defined
2朝巫、ZeroDivisionError
當(dāng)除數(shù)為零的時候鸿摇,會引發(fā)ZeroDivisionError異常。
a = 10/0
print(a)
# ZeroDivisionError: division by zero
**3劈猿、SyntaxError **
當(dāng)解釋器發(fā)現(xiàn)語法錯誤時拙吉,會引發(fā)SyntaxError異常潮孽。
a = 10
if a == 10
print('賓果!')
# SyntaxError: invalid syntax
4筷黔、IndexError
當(dāng)使用序列中不存在的索引時往史,會引發(fā)IndexError異常。
list = [1,2,3,4]
a = list[4]
print(a)
# IndexError: list index out of range
5佛舱、KeyError
當(dāng)使用映射中不存在的鍵時椎例,會引發(fā)KeyError異常。
mydict = {'name':'張三','age':18}
address = mydict['address']
print(address)
# KeyError: 'address'
**6请祖、FileNotFoundError **
試圖打開不存在的文件時订歪,會引發(fā)FileNotFoundError。
file = open('a.txt','r')
# FileNotFoundError: [Errno 2] No such file or directory: 'a.txt'
7肆捕、AttributeError
當(dāng)嘗試訪問未知對象屬性時刷晋,會引發(fā)AttributeError異常。
class Settings():
def _init_(self):
self.scren_width=1200
self.screen_height=800
self.bg_color=(230,230,230)
if __name__ == '__main__':
a = Settings()
print(a.scren_width)
# AttributeError: 'Settings' object has no attribute 'scren_width'
2.2慎陵、異常處理
在python中眼虱,try-except語句定義了監(jiān)控異常的一段代碼,并提供了處理異常的機制荆姆。
1蒙幻、捕獲指定異常
try:
# 可能會出現(xiàn)異常的語句塊
except <異常種類>:
# 異常處理代碼
print('程序開始')
try:
a = 10/0
print(a)
except ZeroDivisionError as e:
print('捕獲異常-零不可以是除數(shù)',e)
print('程序繼續(xù)執(zhí)行')
# 程序開始
# 捕獲異常-零不可以是除數(shù) division by zero
# 程序繼續(xù)執(zhí)行
注意,exception后捕獲的異常必須和try代碼塊中出現(xiàn)的異常種類一致胆筒,才可以捕獲,否則依然會出現(xiàn)異常诈豌,影響其后代碼的執(zhí)行仆救。
print('程序開始')
try:
a = 10/0
print(a)
except FileNotFoundError as e:
print('捕獲異常-文件找不到',e)
print('程序繼續(xù)執(zhí)行')
# ZeroDivisionError: division by zero
2、捕獲多個異常
捕獲多個異常有兩種方式矫渔,第一種是一個except同時處理多個異常彤蔽,不區(qū)分優(yōu)先級。
try:
# 可能會出現(xiàn)異常的語句塊
except (<異常名1>, <異常名2>, ...):
# 異常處理代碼
print('程序開始')
try:
num1 = int(input('請輸入除數(shù)'))
num2 = int(input('請輸入被除數(shù)'))
print(str(num1)+'除以'+str(num2)+'的結(jié)果是',str(num1/num2))
except (ZeroDivisionError,ValueError):
print('出現(xiàn)異常了')
print('程序繼續(xù)執(zhí)行')
還有第二種方式庙洼,是區(qū)分優(yōu)先級的顿痪。
try:
# 可能會出現(xiàn)異常的語句塊
except <異常種類1>:
# 異常處理代碼1
except <異常種類2>:
# 異常處理代碼2
except <異常種類3>:
# 異常處理代碼3
print('程序開始')
try:
num1 = int(input('請輸入除數(shù)'))
num2 = int(input('請輸入被除數(shù)'))
print(str(num1)+'除以'+str(num2)+'的結(jié)果是',str(num1/num2))
except ZeroDivisionError as e1:
print('出現(xiàn)異常了',e1)
except ValueError as e2:
print('出現(xiàn)異常了',e2)
print('程序繼續(xù)執(zhí)行')
3、異常中的else
如果try語句沒有捕獲到任何的錯誤信息油够,就不再執(zhí)行任何except語句蚁袭,而是會執(zhí)行else語句。
try:
# 可能會出現(xiàn)異常的語句塊
except <異常種類1>:
# 異常處理代碼1
except <異常種類2>:
# 異常處理代碼2
except <異常種類3>:
# 異常處理代碼3
else:
# try語句中沒有異常則執(zhí)行此段代碼
import os
print('程序開始執(zhí)行')
try:
wfile = open('2.txt','w',encoding='utf-8')
wfile.write('這是測試文件寫入的內(nèi)容')
except IOError as e:
print('IO異常',2)
else:
print('內(nèi)容寫入成功')
wfile.close()
print('程序繼續(xù)執(zhí)行')
# 程序開始執(zhí)行
# 內(nèi)容寫入成功
# 程序繼續(xù)執(zhí)行
4石咬、捕獲所有的異常
當(dāng)程序中出現(xiàn)大量異常時揩悄,捕獲這些異常是非常麻煩的。這時鬼悠,我們可以在except子句中不指明異常的類型删性,這樣亏娜,不管發(fā)生何種類型的異常,都會執(zhí)行except里面的處理代碼蹬挺。
print('程序開始')
try:
num1 = int(input('請輸入除數(shù)'))
num2 = int(input('請輸入被除數(shù)'))
print(str(num1)+'除以'+str(num2)+'的結(jié)果是',str(num1/num2))
except:
print('出現(xiàn)異常了')
print('程序繼續(xù)執(zhí)行')
5维贺、終止行為(finally)
在程序中,無論是否捕捉到異常巴帮,都必須要執(zhí)行某件事情幸缕,例如關(guān)閉文件、釋放鎖等晰韵,這時可以提供finally語句處理发乔。通常情況下,finally用于釋放資源雪猪。
str = 'hello python'
try:
a = int(str)
except IndexError as e1:
print('出現(xiàn)異常',e1)
except KeyError as e2:
print('出現(xiàn)異常',e2)
except ValueError as e3:
print('出現(xiàn)異常',e3)
else:
print('try內(nèi)沒有異常')
finally:
print('無論異常與否,都會執(zhí)行我')
3栏尚、raise語句
python是否可以在程序的指定位置手動拋出一個異常?答案是肯定的只恨,python 允許我們在程序中手動設(shè)置異常译仗,使用 raise 語句即可。類似Java中的throw官觅。
語法:raise [exceptionName [(reason)]]
其中纵菌,用 [] 括起來的為可選參數(shù),其作用是指定拋出的異常名稱休涤,以及異常信息的相關(guān)描述咱圆。如果可選參數(shù)全部省略,則 raise 會把當(dāng)前錯誤原樣拋出功氨;如果僅省略 (reason)序苏,則在拋出異常時,將不附帶任何的異常描述信息捷凄。
簡而言之就是使用raise語句能顯示地觸發(fā)異常忱详。
格式如下:
1、raise 異常類名 引發(fā)指定異常類的實例
2跺涤、raise 異常類對象 引發(fā)指定異常類的實例
3匈睁、raise 重新引發(fā)剛剛發(fā)生的異常
3.1、使用類名引發(fā)異常
print('程序開始執(zhí)行')
try:
a = input('請輸入一個數(shù)字')
#判斷用戶輸入的是否為數(shù)字
if(not a.isdigit()):
raise ValueError("輸入的必須是數(shù)字") #人為扔出異常
except ValueError as e:
print("引發(fā)異常:",repr(e))
print('程序繼續(xù)執(zhí)行')
# 程序開始執(zhí)行
# 請輸入一個數(shù)字wasd
# 引發(fā)異常: ValueError('輸入的必須是數(shù)字')
# 程序繼續(xù)執(zhí)行
3.2桶错、使用異常類的實例引發(fā)異常
print('程序開始執(zhí)行')
try:
a = input('請輸入一個數(shù)字')
#判斷用戶輸入的是否為數(shù)字
if(not a.isdigit()):
err = ValueError()
raise err
except ValueError as e:
print("引發(fā)異常:",repr(e))
print('程序繼續(xù)執(zhí)行')
3.3航唆、raise傳遞異常
不帶任何參數(shù)的raise語句,可以再次引發(fā)剛剛發(fā)生過的異常牛曹,作用就是向外傳遞異常佛点。
print('程序開始執(zhí)行')
try:
a = input('請輸入一個數(shù)字')
#判斷用戶輸入的是否為數(shù)字
if(not a.isdigit()):
raise ValueError("輸入的必須是數(shù)字")
except ValueError as e:
print("引發(fā)異常:",repr(e))
raise
print('程序繼續(xù)執(zhí)行')
# ValueError: 輸入的必須是數(shù)字
4、assert語句
assert語句又稱作斷言,指的是期望用戶滿足指定的條件超营。
當(dāng)用戶定義的約束條件不滿足的時候鸳玩,它會觸發(fā)AssertionError異常,所以assert語句可以當(dāng)做條件式的raise語句演闭。
assert語句格式如下:
assert 邏輯表達(dá)式不跟,data
相當(dāng)于:
if not 邏輯表達(dá)式:
raise AssertionError(data)
assert后面緊跟一個邏輯表達(dá)式,相當(dāng)于條件米碰。Data通常是一個字符串窝革,當(dāng)條件為false時作為異常的描述信息。
print('程序開始執(zhí)行')
a = int(input('請輸入除數(shù)'))
assert a != 0,'除數(shù)不可以為0'
# AssertionError: 除數(shù)不可以為0
5吕座、自定義異常
python允許我們自定義異常虐译,只需要兩步:
1、創(chuàng)建一個繼承Exception類的子類吴趴,就是自定義異常類漆诽。
2、當(dāng)遇到自己設(shè)定的錯誤時锣枝,使用raise語句拋出自定義的異常厢拭。
#自定義異常類
class MyErr(Exception):
def __init__(self,args):
self.args = args
#觸發(fā)自定義異常
if __name__ == '__main__':
print('程序開始執(zhí)行')
try:
raise MyErr('這是我自定義的異常')
except MyErr as e:
print('出現(xiàn)的異常為',e.args)
6、總結(jié)
這次主要針對Python的異常進(jìn)行介紹撇叁,包括異常類供鸠、拋出和捕捉系統(tǒng)內(nèi)置的異常、拋出和捕捉自定義異常陨闹,大家應(yīng)該深入了解了異常產(chǎn)生的原理楞捂,并知道如何在程序中運行它們。