第11課 異常處理

一、異常處理的意義

1. 異常機(jī)制已經(jīng)成為衡量一門編程語言是否成熟的標(biāo)準(zhǔn)之一趟卸,使用異常處理機(jī)制的Python程序會有更好的容錯性。

2. 沒有人能夠保證自己寫的程序永遠(yuǎn)不會出錯,既是程序沒有錯誤谷饿,也不能保證用戶按你的意圖來輸入窄赋,另外還有系統(tǒng)的穩(wěn)定性傅联,計(jì)算硬件是否損壞秸苗,網(wǎng)絡(luò)掉線等諸多情況。

二恢暖、異常處理機(jī)制

1. 使用try...except捕獲異常

1)例如排监,通常在程序運(yùn)行時,用戶可以隨意輸入杰捂,程序不會因?yàn)橛脩舻妮斎氩缓戏ǘ蝗婚g退出舆床,而是向用戶提示輸入不合法,并請用戶再次輸入嫁佳。

那么我們就希望有一種強(qiáng)大的if塊來解決這個非法輸入的問題:

if 用戶輸入不合法:

? ? alert 輸入不合法

? ? go retry

else:

????#業(yè)務(wù)實(shí)現(xiàn)代碼

2)但是“用戶輸入不合法”這個條件怎么定義呢挨队?我們可以使用正則表達(dá)式與用戶的輸入進(jìn)行匹配。但現(xiàn)實(shí)中不合法的情況非常多蒿往,想讓程序一次處理所有的錯誤盛垦,我們可以將上面的偽代碼修改為:

if 一切正常:

? ? #業(yè)務(wù)實(shí)現(xiàn)代碼

就是:

? ? alert 輸入不合法

? ? goto retry

3) 但“一切正常”依然是很抽象的瓤漏,無法轉(zhuǎn)化成代碼腾夯。在這種情形下Python提供了一種假設(shè):如果程序可以順利運(yùn)行,那么就是“一切正呈叱洌”蝶俱。由此得出Python異常處現(xiàn)機(jī)制的語法結(jié)構(gòu):

try:

? ? #業(yè)務(wù)實(shí)現(xiàn)代碼

except(Error1, Error2, ....) as e:

? ? alert 輸入不合法

? ? goto retry

4) 這樣如果執(zhí)行try塊里的業(yè)務(wù)實(shí)現(xiàn)代碼是出現(xiàn)異常,系統(tǒng)會自動生成一個異常對象饥漫,該異常對象被提交給Python解釋器榨呆,這個過程被稱為引發(fā)異常。

5)當(dāng)Python解釋器收到異常對象時趾浅,會尋找處理該異常對象的except塊愕提,如果找到合適的except塊馒稍,則把該過程稱為捕捉異常皿哨。如果Python解釋器找到不捕獲異常的except塊浅侨,則運(yùn)行時環(huán)境終止,Python解釋器也將退出证膨。

6)不管代碼塊是否處于try中如输,或except塊中,只要執(zhí)行該代碼時了現(xiàn)了異常央勒,系統(tǒng)總會自動生成一個Error對象不见。

7) try 可以有多個except塊,這是為了針對不同的異常類提供不同的異常處理方式崔步。當(dāng)系統(tǒng)發(fā)生不同意外情況時稳吮,系統(tǒng)會生成不同的異常對象。如果try被執(zhí)行一次井濒,灶似,則try后面只有一個except被執(zhí)行,除非放在循環(huán)中瑞你,使用continue開始下一次循環(huán)酪惭。

2. 異常類

1)Python的所有異常類的基類是BaseException, 但是如果用戶果自定義異常,則一概繼承Exception類者甲。

2)BaseException的主要子類是Exception春感,所在不管是系統(tǒng)的異常類,還是用戶自定義異常類虏缸,都是從Exception派生鲫懒。

3)異常捕獲實(shí)例:

>>> import sys

>>> try:

a = int(sys.argv[1]) # 代表當(dāng)前運(yùn)行的程序所提供的第一個參數(shù)

b = int(sys.argv[2])# 代表當(dāng)前運(yùn)行的程序所提供的第二個參數(shù)

c = a/b

print("您輸入的兩個數(shù)相除的結(jié)果是:",c)

except IndexError:

print("索引錯誤:運(yùn)行程序時輸入的參數(shù)個數(shù)不夠")

except ValueError:

print("數(shù)值錯誤:程序只能接受整數(shù)參數(shù)")

except ArithmeticError:

print("算術(shù)錯誤")

except Exception:

print("未知異常")

3. 多異常捕獲:指一個Except塊可以捕獲多種類型的異常。例如:

>>> import sys

>>> try:

a = int(sys.argv[1])

b = int(sys.argv[2])

c = a/b

print("您輸入的兩個數(shù)相除的結(jié)果是:",c)

except (IndexError, ValueError, ArithmeticError):

print("程序發(fā)生了數(shù)組越界刽辙、格式錯誤窥岩、算術(shù)異常之一")

except: # 此處的省略也是合法的,一般放在最后

print("未知異常")

程序發(fā)生了數(shù)組越界扫倡、格式錯誤谦秧、算術(shù)異常之一

4. 訪問異常信息

1)如果程序需要在except塊中訪問異常對象的相關(guān)信息,則可以通過為異常對象聲明變量來實(shí)現(xiàn)撵溃。

2)所在的異常對象都包含如下幾個對象和方法:

args: 該屬性返回異常的錯誤編號和描述字符串

errno:該屬性返回異常的錯誤編號

strerror:該屬性返回異常的描述字符串

with_traceback():通過該方法可以處理異常的傳播軌跡

3)程序訪問異常信息實(shí)例:

>>> def foo():

try:

fis = open("a.txt")

except Exception as e:

print(e.args)

print(e.errno)

print(e.strerror)

>>> foo()

#運(yùn)行結(jié)果如下:

(2, 'No such file or directory')

2

No such file or directory

5. else塊

1) 在Python異常處理流程中還可添加一個else塊疚鲤,當(dāng)try塊沒有出現(xiàn)異常時,程序會執(zhí)行else塊缘挑。

例如:

>>> s = input("請輸入除數(shù):")

請輸入除數(shù):5

>>> try:

result = 20/int(s)

print('20除以%s的結(jié)果是:%g'%(s,result))

except ValueError:

print('值錯誤集歇,您必須輸入數(shù)值')

except ArithmeticError:

print('算術(shù)錯誤,您不能輸入0')

else:

print('沒有出現(xiàn)異常')

#運(yùn)行結(jié)果如下:

20除以5的結(jié)果是:4

沒有出現(xiàn)異常

2)實(shí)際上大部分語言異常處理都沒有else塊语淘,可以將else塊的內(nèi)容直接放到try后面诲宇。但Python異常處理使用else塊也不是多余的語法际歼。因?yàn)樵趀lse塊中的異常不會被except捕獲,該異常會傳給Python解釋器導(dǎo)致程序中止姑蓝。

3)如果希望某段代碼的異常鹅心,能被后面的except捕獲,那么就應(yīng)該放在try塊中纺荧;如果不希望被except捕獲旭愧,就應(yīng)該放在else塊中。

6. 使用finally回收資源

1)為了能夠保證回收try塊中打開的一些物理資源(如數(shù)據(jù)庫連接宙暇、網(wǎng)絡(luò)連接和磁盤文件)输枯,異常處理機(jī)制提供了finally塊。

2)Python 完整的異常處理語法結(jié)構(gòu)如下:

try:

? ? #業(yè)務(wù)實(shí)現(xiàn)代碼

except SubException1 as e:

? ? #異常處理塊1

except SubException2 as e:

? ? #異常處理塊2

else:

? ? #正常處理塊

finally:

? ? #資源回收塊


三占贫、使用raise引發(fā)異常

1. 如果程序中數(shù)據(jù)或執(zhí)行與現(xiàn)實(shí)的需求不符桃熄,但是系統(tǒng)不會判斷這樣的異常,只能程序員來決定是否引發(fā)異常型奥,此時可以使用raise語句來完成這種自行引發(fā)的異常瞳收。

2. raise語句三種常見的用法:

1) 單獨(dú)一個raise,該語句引發(fā)當(dāng)前上下文中捕獲的異常桩引,或默認(rèn)引發(fā)RuntimeError異常缎讼。

2)raise后帶一個異常類,該語句引發(fā)指定的異常類坑匠。

3)raise后帶一個異常對象血崭,該語句引發(fā)制定的異常對象。

以上三種最終都是引發(fā)一個異常實(shí)例厘灼,每次只能引發(fā)一個異常實(shí)例夹纫。

3. 用戶引發(fā)異常的兩種方式:raise和except,例如:

>>> def main():

try: # 使用try...except來捕獲異常设凹,此時出現(xiàn)異常也不會傳給調(diào)用它的main()函數(shù)

mtd(3)

except Exception as e:

print('程序出現(xiàn)異常類是:',e)

mtd(3) #不使用try...except來捕獲異常舰讹,異常會傳播并導(dǎo)致程序中止

>>> def mtd(a):

if a>0:

raise ValueError("a的值大于0,不符合要求")

>>> main()


四、異常的傳播軌跡

1. 異常只要沒有被完全捕獲闪朱,異常就會從發(fā)生異常的函數(shù)或方法向外傳播月匣,首先傳給該函數(shù)或方法的調(diào)用者,然后奋姿,锄开,直到傳給Python解釋器,Python解釋器就會中止程序称诗,并打印異常傳播的軌跡信息萍悴。所以通常我們看到大段的異常信息,并不一定發(fā)生很多嚴(yán)重的問題,可能只是一個異常引發(fā)的癣诱。

2. Python專門提供trackback模塊來處理異常傳播的軌跡计维,兩種常用的方法是:

1)trackback.print_exc(): 將異常傳播軌跡輸出到控制臺或文件中。

2) format_exc():將異常傳播軌跡轉(zhuǎn)換成字符串撕予。

五鲫惶、異常處理規(guī)則

1.? 不要過度使用異常處理,注意以下兩點(diǎn):

1) 需要編寫錯誤處理代碼嗅蔬,而不是簡單的用異常來代替處理剑按。

2)? 不能用異常來代替流程控制疾就。

2.? 不要使用過度龐大的try塊:try塊越大澜术,發(fā)生異常的可能性就越大。而且在龐大的try塊后勢必有大量的except塊猬腰,這時要判斷各個塊之間的邏輯關(guān)系鸟废,編寫程序會變得更加復(fù)雜。

3. 不要忽略捕捉到的異常: 程序應(yīng)該盡量修改異常姑荷,保證程序繼續(xù)運(yùn)行盒延;不要將本層的異常傳給上一層去處理。

六鼠冕、本節(jié)回顧

1. 你怎么理解異常處理機(jī)制添寺?

2. Python異常處理的5個關(guān)鍵字是什么?(try\ except\else\finally\raise)

3. 如何使用raise引發(fā)異常懈费?

4. 如何獲得異常的源頭和軌跡计露?

5.異常處理的原則有哪些?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末憎乙,一起剝皮案震驚了整個濱河市票罐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌泞边,老刑警劉巖该押,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異阵谚,居然都是意外死亡蚕礼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門梢什,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奠蹬,“玉大人,你說我怎么就攤上這事绳矩≌秩螅” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵翼馆,是天一觀的道長割以。 經(jīng)常有香客問我金度,道長,這世上最難降的妖魔是什么严沥? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任猜极,我火速辦了婚禮,結(jié)果婚禮上消玄,老公的妹妹穿的比我還像新娘跟伏。我一直安慰自己,他們只是感情好翩瓜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布受扳。 她就那樣靜靜地躺著,像睡著了一般兔跌。 火紅的嫁衣襯著肌膚如雪勘高。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天坟桅,我揣著相機(jī)與錄音华望,去河邊找鬼。 笑死仅乓,一個胖子當(dāng)著我的面吹牛赖舟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播夸楣,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼宾抓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了裕偿?” 一聲冷哼從身側(cè)響起洞慎,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嘿棘,沒想到半個月后劲腿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸟妙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年焦人,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片重父。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡花椭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出房午,到底是詐尸還是另有隱情矿辽,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站袋倔,受9級特大地震影響雕蔽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宾娜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一批狐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧前塔,春花似錦嚣艇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至该抒,卻和暖如春慌洪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背凑保。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留涌攻,地道東北人欧引。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像恳谎,于是被迫代替她去往敵國和親芝此。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容