Python基礎(chǔ)手冊26——錯誤 & 異常

一氮凝、錯誤和異常

1、錯誤

從軟件方面來講罩阵,錯誤通常是語法或邏輯上的竿秆。語法錯誤會導(dǎo)致程序代碼不能被解釋器解釋稿壁,這些錯誤必須在程序執(zhí)行前糾正幽钢。當程序的語法正確后,剩下的就是邏輯錯誤了傅是。邏輯錯誤可能是由于不完整或是不合法的代碼邏輯所致匪燕,還可能是由于代碼邏輯無法生成或執(zhí)行。

編譯時會檢查語法錯誤喧笔,編譯完成后 Python 解釋器會在程序運行時檢測邏輯錯誤帽驯。當檢測到一個錯誤,Python 解釋器就引發(fā)一個異常书闸,并顯示異常的詳細信息尼变。程序員可以根據(jù)這些信息迅速定位問題并進行調(diào)試。


2浆劲、異常

異常處理通常分為兩個階段:首先是解釋器在執(zhí)行代碼過程中發(fā)生錯誤并引起異常嫌术,異常會在錯誤檢測到的地方引發(fā),并將當前流打斷梳侨,然后是檢測異常并執(zhí)行相關(guān)的處理程序蛉威。

異常引發(fā)后日丹,可以調(diào)用很多不同的操作走哺。可以是忽略錯誤(記錄錯誤但不采取任何措施)哲虾,或是減輕問題的影響后設(shè)法繼續(xù)執(zhí)行程序丙躏。所有的這些操作都代表一種程序的繼續(xù)择示,關(guān)鍵是程序員在錯誤發(fā)生時可以指示程序如何執(zhí)行。

類似 Python 這樣支持引發(fā)和處理異常(這更重要)的語言晒旅,可以讓開發(fā)人員可以在錯誤發(fā)生時更直接地控制它們栅盲。程序員不僅僅有了檢測錯誤的能力,還可以在它們發(fā)生時采取更可靠的補救措施废恋。由于有了運行時管理錯誤的能力谈秫,應(yīng)用程序的健壯性有了很大的提高。


常見的異常情況

NameError 表示我們訪問了一個沒有初始化的變量鱼鼓。

任何數(shù)值被零除都會導(dǎo)致一個 ZeroDivisionError 異常拟烫。

SyntaxError 異常是語法錯誤,是唯一不是在運行時發(fā)生的異常迄本。它代表 Python 代碼中有一個不正確的語法結(jié)構(gòu)硕淑,在它改正之前程序無法執(zhí)行。這些錯誤一般都是在編譯時發(fā)生嘉赎,Python 解釋器無法把你的腳本轉(zhuǎn)化為 Python 字節(jié)代碼置媳,當然這也可能是你導(dǎo)入一個有缺陷的模塊的時候。

IndexError 異常在你嘗試使用一個超出范圍的值來索引序列時引發(fā)公条。

映射對象拇囊,例如字典,是依靠關(guān)鍵字(keys)訪問數(shù)據(jù)值的靶橱。如果使用錯誤的或是不存在的鍵請求字典就會引發(fā)一個 KeyError 異常寂拆。

類似嘗試打開一個不存在的磁盤文件一類的操作會引發(fā)一個 FileNotFoundError 異常。

屬性和方法被定義后抓韩,我們可以使用熟悉的點操作符訪問它纠永,但如果是沒有定義的屬性,將導(dǎo)致一個 AttributeError 異常谒拴。


二尝江、try 語句

要給你的代碼添加錯誤檢測及異常處理,只要將它們封裝在 try-except 語句當中英上。 try 子句的代碼塊炭序,就是你打算監(jiān)測的代碼,檢查有無異常發(fā)生苍日。except 句子的代碼塊惭聂,則是你處理異常的代碼。

在程序運行時相恃,解釋器嘗試執(zhí)行 try 子句塊里的所有代碼辜纲,如果代碼塊完成后沒有異常發(fā)生,就會忽略 except 子句繼續(xù)執(zhí)行。當 try 子句塊中發(fā)生異常時耕腾,Python 解釋器會依次檢查 except 子句见剩,直到找到與異常匹配的子句,并執(zhí)行其中的代碼塊扫俺。

當找到一個匹配的 except 子句時苍苞,異常就被賦給 except 子句中 as 關(guān)鍵字后面的目標,然后執(zhí)行 excep 子句的 suite狼纬。所有 except 子句必須有一個可執(zhí)行塊羹呵。

try 語句塊中異常發(fā)生點后的剩余語句永遠不會執(zhí)行。 一旦一個異常被引發(fā)疗琉,就必須決定控制流下一步到達的位置担巩。try子句代碼塊中的剩余代碼將被忽略,解釋器將搜索處理器没炒,一旦找到涛癌,就開始執(zhí)行處理器中的代碼。

如果沒有找到合適的處理器送火,那么異常就向上移交給調(diào)用者去處理拳话。如果在上層調(diào)用者也沒找到對應(yīng)處理器,該異常會繼續(xù)被向上移交种吸,直到找到合適處理器弃衍。如果到達最頂層仍然沒有找到對應(yīng)處理器,那么就認為這個異常是未處理的坚俗,Python 解釋器會顯示出跟蹤返回消息镜盯,然后退出。

如果同一異常存在兩個嵌套處理程序猖败,并且內(nèi)部處理程序的 try 子句中發(fā)生異常速缆,則外部處理程序?qū)⒉惶幚懋惓!H绻?except 子句頭部的一個表達式引發(fā)了異常恩闻, 那么就會中斷原異常處理器的搜索艺糜, 而在外層代碼和調(diào)用棧上搜索新的異常處理器(就好像是整個 try 語句發(fā)生了異常一樣)。

1幢尚、try-except 語句

我們使用 try-except 語句進行異常的監(jiān)控破停,并且對監(jiān)測到的異常進行處理。最常見的 try-except 語句語法如下所示尉剩。它由 try 子句和 except 子句組成真慢,也可以有一個可選的 as 語句來保存錯誤原因。

try:
    try_suite             # 監(jiān)控這里的異常
except Exception[as reason]:
    except_suite       # 異常處理代碼


2理茎、處理多個異常的 except 語句

我們可以在一個 except 子句里指定并處理多個異常黑界。except 語句在指定多個異常時要求異常被放在一個元組里:

try:
    try_suite    
except (Exception1, Exception2)[as reason]:
    suite_for_Exception1_and_Exception2


3管嬉、帶有多個 except 的 try 語句

你可以把多個 except 語句連接在一起,處理一個 try 塊中可能發(fā)生的多種異常园爷,我們可以分別為每個異常類型分別創(chuàng)建對應(yīng)處理程序,這樣就可以更加細致的處理錯誤并得到更詳細的錯誤信息式撼。

try:
    try_suite    
except Exception1[as reason1]:
    suite_for_exception_Exception1
except Exception2[as reason2]:
    suite_for_exception_Exception2

同樣童社,首先嘗試執(zhí)行 try 子句,如果沒有錯誤著隆,忽略所有的 except 從句繼續(xù)執(zhí)行扰楼。如果發(fā)生異常,解釋器將在這一串處理器(except 子句)中從上到下查找匹配的異常美浦。如果找到對應(yīng)的處理器弦赖,執(zhí)行流將跳轉(zhuǎn)到這里。

4浦辨、捕獲所有異常

如果查詢異常類繼承的樹結(jié)構(gòu)蹬竖,我們會發(fā)現(xiàn) Exception 類是在最頂層的,所以我們可以在 except 子句中通過指定 Exception 異常來捕獲所有的異常:

try:
    pass
except Exception [as e]:
    # error occurred, log 'e', etc.

另一個我們不太推薦的方法是使用 裸 except 子句來匹配所有的異常:

try:
    pass
except:
    # error occurred, etc.

雖然這樣的代碼可以捕獲大多異常流酬,但它不是好的 Python 編程樣式币厕。它會捕獲所有異常,你可能會忽略掉重要的錯誤芽腾,正常情況下這些錯誤應(yīng)該讓調(diào)用者知道并做一定處理旦装。通常我們只是在多個 except 組合子句的最后的 except 子句中來捕捉 Exception 異常。

Python 提供給程序員的 try-except 語句是為了更好地跟蹤潛在的錯誤并在代碼里準備好處理異常的邏輯摊滔。它的目的是減少程序出錯的次數(shù)并在出錯后仍能保證程序正常執(zhí)行阴绢。

5、異常參數(shù)

異常也可以有參數(shù)艰躺,當異常被引發(fā)后參數(shù)是作為附加幫助信息傳遞給異常處理器的呻袭。標準內(nèi)建異常提供至少一個參數(shù),指示異常原因的一個字符串腺兴。

異常的參數(shù)可以在處理器里忽略棒妨,但 Python 中可以在 except 關(guān)鍵字的后面使用過 as 關(guān)鍵字來保存這個值。我們已經(jīng)在上邊接觸到相關(guān)內(nèi)容:要想訪問提供的異常原因含长,你必須保留一個變量來保存這個參數(shù)券腔。把這個參數(shù)放在 as 語句的后面批钠,并接在 except 語句要處理的異常后面啡省。except 語句的這個語法可以被擴展為:

# single exception
except Exception[as reason]:
    suite_for_Exception_with_Argument


# multiple exceptions
except (Exception1, Exception2, ..., ExceptionN)[as reason]:
    suite_for_Exception1_to_ExceptionN_with_Argument

reason 將會是一個包含來自導(dǎo)致異常的代碼的診斷信息的類實例栋猖。異常參數(shù)自身會組成一個元組躬贡,并存儲為類實例(異常類的實例)的屬性姨涡。上邊的第一種用法中幌蚊,reason 將會是一個 Exception 類的實例翻伺。

對于大多內(nèi)建異常畴蒲,也就是從 StandardError 派生的異常,這個元組只包含一個指示錯誤原因的字符串染簇。一般說來参滴,異常的名字已經(jīng)是一個滿意的線索了,但這個錯誤字符串會提供更多的信息锻弓。操作系統(tǒng)或其他環(huán)境類型的錯誤砾赔,例如 IOError ,元組中會把操作系統(tǒng)的錯誤編號放在錯誤字符串前青灼。

6暴心、else 子句

我們已經(jīng)看過 else 語句段配合其他的 Python 語句,比如條件和循環(huán)杂拨。至于 try-except 語句专普,它的功能和你所見過的其他 else 語句沒有太多的不同:在 try 語句范圍中沒有異常被檢測到時,執(zhí)行 else 子句弹沽。

else 子句范圍中的任何代碼運行前檀夹,try 范圍中的所有代碼必須完全執(zhí)行成功(也就是,結(jié)束前沒有引發(fā)異常)策橘。

try:
    pass
except Exception[as reason]:
    pass
else:
    pass


7击胜、finally 子句

finally 子句是無論異常是否發(fā)生、是否捕捉都會執(zhí)行的一段代碼役纹。你可以將 finally 子句僅僅配合 try 子句一起使用偶摔,也可以和 try-except(else 也是可選的,但是必須和 except 子句配合使用)一起使用促脉。

try:
    pass
except Exception[as reason]:
    pass
else:
    pass
finally:
    pass

另一種使用 finally 的方式是 finally 單獨和 try 連用辰斋。

 try:
    pass
finally:
    pass

當在 try 子句范圍中產(chǎn)生一個異常時,會立即跳轉(zhuǎn)到 finally 語句段瘸味。當 finally 中的所有代碼都執(zhí)行完畢后宫仗,會繼續(xù)向上一層引發(fā)異常。


三旁仿、觸發(fā)異常

到目前為止藕夫,我們所見到的異常都是由解釋器引發(fā)的,由于執(zhí)行期間的錯誤而引發(fā)枯冈。程序員在編寫 API 時可能希望手動觸發(fā)異常毅贮,為此 Python 提供了一種機制可以讓程序員明確的觸發(fā)異常,就是 raise 語句尘奏。

1滩褥、raise 語句

rasie 一般的用法是:
raise [SomeException [, args [, traceback]]]

第一個參數(shù) SomeExcpetion 是觸發(fā)異常的名字。如果有炫加,它必須是一個異常的類或?qū)嵗寮澹绻衅渌麉?shù)(args 或 traceback)铺然,則必須提供 SomeExcpetion。

第二個符號為可選的 args(比如參數(shù)酒甸,值)來傳給異常魄健。這可以是一個單獨的對象也可以是一個對象的元組。如果 args 原本就是元組插勤,那么就將其傳給異常去處理沽瘦;如果 args 是一個單獨的對象,生成只有一個元素的元組(就是單元素元組)饮六。大多數(shù)情況下其垄,使用單一的字符串用來指示錯誤的原因苛蒲。如果傳的是元組卤橄,通常的組成是一個錯誤字符串,一個錯誤編號臂外,可能還有一個錯誤的地址窟扑,比如文件,等等漏健。

最后一項參數(shù)嚎货,traceback,同樣是可選的(實際上很少用它)蔫浆,如果有的話殖属,則是當異常觸發(fā)時新生成的一個用于異常-正常化(exception—normally)的追蹤(traceback)對象瓦盛。當你想重新引發(fā)異常時洗显,第三個參數(shù)很有用(可以用來區(qū)分先前和當前的位置)。如果沒有這個參數(shù)原环,就填寫 None挠唆。

最常見的用法為 SomeException 是一個類。不需要其他的參數(shù)嘱吗,但如果有的話玄组,可以是一個單一對象參數(shù),一個參數(shù)的元組谒麦,或一個異常類的實例俄讹。如果參數(shù)是一個實例,可以由給出的類及其派生類實例化(已存在異常類的子集)绕德。若參數(shù)為實例颅悉,則不能有更多的其他參數(shù)。

2迁匠、斷言

斷言是一句必須等價于布爾真的判定剩瓶;此外驹溃,發(fā)生異常也意味著表達式為假。斷言可以簡簡單單的想象為raise-if-not 語句延曙。測試一個表達式,如果返回值是假,觸發(fā)異常豌鹤。如果斷言成功不采取任何措施(類似語句),否則觸發(fā) AssertionError (斷言錯誤)的異常枝缔。

assert expression[, arguments]

AssertionError 異常和其他的異常一樣可以用 try-except 語句塊捕捉布疙,但是如果沒有捕捉,它將終止程序運行而且提供一個如上的 traceback愿卸。

下面是我們?nèi)绾斡?try-except 語句捕獲 AssertionError 異常:


《Python基礎(chǔ)手冊》系列:

Python基礎(chǔ)手冊 1 —— Python語言介紹
Python基礎(chǔ)手冊 2 —— Python 環(huán)境搭建(Linux)
Python基礎(chǔ)手冊 3 —— Python解釋器
Python基礎(chǔ)手冊 4 —— 文本結(jié)構(gòu)
Python基礎(chǔ)手冊 5 —— 標識符和關(guān)鍵字
Python基礎(chǔ)手冊 6 —— 操作符
Python基礎(chǔ)手冊 7 —— 內(nèi)建函數(shù)
Python基礎(chǔ)手冊 8 —— Python對象
Python基礎(chǔ)手冊 9 —— 數(shù)字類型
Python基礎(chǔ)手冊10 —— 序列(字符串)
Python基礎(chǔ)手冊11 —— 序列(元組&列表)
Python基礎(chǔ)手冊12 —— 序列(類型操作)
Python基礎(chǔ)手冊13 —— 映射(字典)
Python基礎(chǔ)手冊14 —— 集合
Python基礎(chǔ)手冊15 —— 解析
Python基礎(chǔ)手冊16 —— 文件
Python基礎(chǔ)手冊17 —— 簡單語句
Python基礎(chǔ)手冊18 —— 復(fù)合語句(流程控制語句)
Python基礎(chǔ)手冊19 —— 迭代器
Python基礎(chǔ)手冊20 —— 生成器
Python基礎(chǔ)手冊21 —— 函數(shù)的定義
Python基礎(chǔ)手冊22 —— 函數(shù)的參數(shù)
Python基礎(chǔ)手冊23 —— 函數(shù)的調(diào)用
Python基礎(chǔ)手冊24 —— 函數(shù)中變量的作用域
Python基礎(chǔ)手冊25 —— 裝飾器
Python基礎(chǔ)手冊26 —— 錯誤 & 異常
Python基礎(chǔ)手冊27 —— 模塊
Python基礎(chǔ)手冊28 —— 模塊的高級概念
Python基礎(chǔ)手冊29 —— 包

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末灵临,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子趴荸,更是在濱河造成了極大的恐慌儒溉,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件发钝,死亡現(xiàn)場離奇詭異顿涣,居然都是意外死亡,警方通過查閱死者的電腦和手機酝豪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門涛碑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人孵淘,你說我怎么就攤上這事蒲障。” “怎么了瘫证?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵揉阎,是天一觀的道長。 經(jīng)常有香客問我痛悯,道長余黎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任载萌,我火速辦了婚禮惧财,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘扭仁。我一直安慰自己垮衷,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布乖坠。 她就那樣靜靜地躺著搀突,像睡著了一般。 火紅的嫁衣襯著肌膚如雪熊泵。 梳的紋絲不亂的頭發(fā)上仰迁,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天甸昏,我揣著相機與錄音,去河邊找鬼徐许。 笑死施蜜,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的雌隅。 我是一名探鬼主播翻默,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼恰起!你這毒婦竟也來了修械?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤检盼,失蹤者是張志新(化名)和其女友劉穎肯污,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體梯皿,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡仇箱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年县恕,在試婚紗的時候發(fā)現(xiàn)自己被綠了东羹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡忠烛,死狀恐怖属提,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情美尸,我是刑警寧澤冤议,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站师坎,受9級特大地震影響恕酸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜胯陋,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一蕊温、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧遏乔,春花似錦义矛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至捻激,卻和暖如春制轰,著一層夾襖步出監(jiān)牢的瞬間前计,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工垃杖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留残炮,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓缩滨,卻偏偏與公主長得像势就,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子脉漏,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

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

  • 一苞冯、簡介 Python最強大的結(jié)構(gòu)之一就是它的異常處理能力,所有的標準異常都使用類來實現(xiàn)侧巨,都是基類Exceptio...
    隨風(fēng)化作雨閱讀 3,073評論 0 1
  • Python異常處理 異常概念: 異常:就是不正常的情況舅锄,程序開發(fā)過程中錯誤和BUG都是補充正常的情況 異常發(fā)生的...
    youngkun閱讀 924評論 0 4
  • 處在大三這樣一個關(guān)鍵的時間點皇忿,身邊的人都在為自己的未來做打算,有的人想去北上廣工作坦仍,有的人要讀研究生鳍烁,有的人要為出...
    那小娜閱讀 458評論 3 3
  • 思考:“我與你”是不帶有任何目的性的相處,文章講的是這種相處好比是“神性在其中”繁扎,這種關(guān)系如果放在母親與孩子之間幔荒,...
    楊雪雪閱讀 63評論 0 0
  • 靈魂沒有內(nèi)涵灌溉,輕飄飄的空殼身體往上飄啊飄梳玫,越來越脫離世界爹梁。 大三最后一個學(xué)期,才開始醒悟提澎,加上身邊老師的呼吁姚垃,...
    橙大仙閱讀 310評論 0 2