使用Python進行異常處理

image
  • 來源 | 愿碼(ChainDesk.CN)內(nèi)容編輯
  • 愿碼Slogan | 連接每個程序員的故事
  • 網(wǎng)站 | http://chaindesk.cn
  • 愿碼愿景 | 打造全學(xué)科IT系統(tǒng)免費課程,助力小白用戶龟劲、初級工程師0成本免費系統(tǒng)學(xué)習(xí)劫樟、低成本進階亏钩,幫助BAT一線資深工程師成長并利用自身優(yōu)勢創(chuàng)造睡后收入延届。
  • 官方公眾號 | 愿碼 | 愿碼服務(wù)號 | 區(qū)塊鏈部落
  • 免費加入愿碼全思維工程師社群 | 任一公眾號回復(fù)“愿碼”兩個字獲取入群二維碼

本文閱讀時長:10min

本文所涉及知識點

  • Python中有哪些異常 讥珍?

  • 使用try ... except子句控制程序流

  • 通過處理異常來處理常見問題

  • 創(chuàng)建和使用自定義異常類

在直接進入代碼并解決這些問題之前余指,讓我們首先了解異常是什么以及處理異常是什么意思毡熏。

什么是異常?


異常是Python中的對象倦蚪。它為我們提供了有關(guān)在程序執(zhí)行期間檢測到的錯誤的信息希坚。在調(diào)試應(yīng)用程序時注意到的錯誤是未處理的異常,因為我們沒有這些異常陵且。在本文后面裁僧,您將學(xué)習(xí)處理這些異常的技巧个束。

在早期回溯中看到的ValueError和IndexError異常是Python中內(nèi)置異常類型的示例 。在下一節(jié)中聊疲,您將了解Python支持的其他一些內(nèi)置異常 茬底。

最常見的異常


讓我們快速回顧一些最常遇到的異常。最簡單的方法是嘗試運行一些錯誤的代碼获洲,讓它報告錯誤回溯的問題阱表!啟動Python解釋器并編寫以下代碼:

image

以下是一些異常情況:

image

正如您所看到的,代碼的每一行都會拋出一個帶有異常類型的錯誤回溯(突出顯示)贡珊。這些是Python中的一些內(nèi)置異常最爬。Python提供BaseException作為所有內(nèi)置異常的基類。但是门岔,大多數(shù)內(nèi)置異常不直接繼承BaseException爱致。相反,它們是從一個名為Exception的類派生而來的寒随,而這個類又繼承自BaseException糠悯。處理程序退出的內(nèi)置異常(例如,SystemExit)直接從BaseException派生牢裳。您還可以創(chuàng)建自己的異常類作為Exception的子類逢防。您將在本文后面了解到這一點。

異常處理

到目前為止蒲讯,我們已經(jīng)看到了異常的發(fā)生方式 現(xiàn)在忘朝,是時候?qū)W習(xí)如何使用try ... except子句來處理這些異常。以下偽代碼顯示了try ... except子句的一個非常簡單的示例:

image

我們來看看前面的代碼片段:

· 首先判帮,程序嘗試執(zhí)行try子句中的代碼局嘁。

· 在執(zhí)行期間,如果出現(xiàn)錯誤(如果發(fā)生異常)晦墙,它將跳出此try子句悦昵。try塊中的其余代碼不會被執(zhí)行。

· 然后晌畅,它在except子句中查找適當?shù)漠惓L幚沓绦虿?zhí)行它但指。

這里使用的 except子句是通用的。它將捕獲try子句中發(fā)生的所有類型的異常抗楔。而不是擁有這個“全能”處理程序棋凳,更好的做法是捕獲您預(yù)期的錯誤并編寫特定于這些錯誤的異常處理代碼。例如连躏,try子句中的代碼可能會拋出AssertionError剩岳。您可以編寫特定的異常處理程序,而不是使用universal except子句入热,如下所示:

image

在這里拍棕,我們有一個except子句專門處理AssertionError晓铆。它還意味著除了AssertionError之外的任何錯誤都將作為未處理的異常漏掉。為此绰播,我們需要使用不同的異常處理程序定義多個except子句骄噪。但是,在任何時候幅垮,只會調(diào)用一個異常處理程序腰池。用一個例子可以更好地解釋這一點。我們來看看下面的代碼片段:

image

該試塊調(diào)用solve_something() 忙芒。此函數(shù)接受一個數(shù)字作為用戶輸入,并斷言該數(shù)字大于零讳侨。如果斷言失敗呵萨,它會直接跳轉(zhuǎn)到處理程序,但AssertionError除外跨跨。

在另一個場景中潮峦,如果> 0,則執(zhí)行solve_something()中的其余代碼勇婴。您會注意到未定義變量x忱嘹,這會導(dǎo)致NameError。此異常由另一個異常子句處理耕渴,但NameError除外拘悦。同樣,您可以為預(yù)期的錯誤定義特定的異常處理程序橱脸。

提高并重新提出異常


Python中的raise關(guān)鍵字用于強制發(fā)生異常础米。換句話說,它引發(fā)了一個異常添诉。語法很簡單; 只需打開Python解釋器并輸入:

>>> raise AssertionError("some error message")

這會產(chǎn)生以下錯誤回溯:

Traceback (most recent call last): 
  File "", line 1, in 
AssertionError :  some error message

在某些情況下屁桑,我們需要重新引發(fā)異常。假設(shè)栏赴,在try子句中蘑斧,您有一個將數(shù)字除以零的表達式。在普通算術(shù)中须眷,這個表達沒有意義竖瘾。這是一個錯誤!這會導(dǎo)致程序引發(fā)一個名為ZeroDivisionError的異常柒爸。如果沒有異常處理代碼准浴,程序?qū)⒅淮蛴″e誤消息并終止。

如果您希望將此錯誤寫入某個日志文件然后終止該程序捎稚,該怎么辦乐横?在這里求橄,您可以使用except子句首先記錄錯誤。然后葡公,使用不帶任何參數(shù)的raise關(guān)鍵字來重新引發(fā)異常罐农。異常將在堆棧中向上傳播。在此示例中催什,它終止程序涵亏。可以使用raise關(guān)鍵字重新引發(fā)異常而不使用任何參數(shù)蒲凶。

這是一個示例气筋,顯示如何重新引發(fā)異常:

image

可以看出,在解決a / b表達式時旋圆,會出現(xiàn)zeroexception的adivision宠默。這是因為變量b的值設(shè)置為0。出于說明目的灵巧,我們假設(shè)此錯誤沒有特定的異常處理程序搀矫。因此,我們將使用general except子句刻肄,在記錄錯誤后重新引發(fā)異常瓤球。如果您想自己嘗試,只需在新的Python文件中編寫前面說明的代碼敏弃,然后從終端窗口運行它卦羡。以下屏幕截圖顯示了上述代碼的輸出:

image

try ... except


可以在try ... except子句中指定可選的else塊。在其他的只發(fā)生ifno異常塊被執(zhí)行的嘗試......除了條款权她。語法如下:

image

在其他塊的前執(zhí)行最后條款虹茶,我們將在接下來的學(xué)習(xí)。

finally......clean it up隅要!


還有其他東西可以添加到try ...除了... else story:一個可選的finally子句蝴罪。顧名思義,此子句中的代碼在關(guān)聯(lián)的try ... except塊的末尾執(zhí)行步清。無論是否引發(fā)異常要门,finally子句(如果指定)將在try ... except子句的末尾執(zhí)行。想象一下它是由Python提供的全天候保證廓啊!以下代碼段顯示了finally塊的運行情況:

image

運行這個簡單的代碼將產(chǎn)生以下輸出:

$ python finally_example1.py
Enter a number: -1
Uh oh..Assertion Error. 
Do some special cleanup 

輸出中的最后一行是finally子句中的print語句欢搜。

帶有和不帶finally子句的代碼片段如下面的屏幕截圖所示。即使except子句指示代碼從函數(shù)返回谴轮,也確保finally子句中的代碼最終執(zhí)行炒瘟。

image

在最后條款通常用于離開功能之前執(zhí)行清理任務(wù)。示例用例是關(guān)閉數(shù)據(jù)庫連接或文件第步。但請注意疮装,為此缘琅,您還可以在Python中使用with語句。

編寫一個新的異常類


創(chuàng)建一個從Exception派生的新異常類是微不足道的廓推。打開Python解釋器并創(chuàng)建以下類:

>>> class GameUnitError(Exception):
...     pass
... 
>>>

就這樣刷袍!我們有一個新的異常類GameUnitError,可以部署了樊展。如何測試此異常呻纹?在Python解釋器中鍵入以下代碼行:

>>> raise GameUnitError("ERROR: some problem with game unit")

引發(fā)新創(chuàng)建的異常將打印以下回溯:

>>> raise GameUnitError("ERROR: some problem with game unit")
Traceback (most recent call last):
  File "", line 1, in 
__main__.GameUnitError: ERROR: some problem with game unit

將GameUnitError類復(fù)制到其自己的模塊gameuniterror.py中,并將其保存在與attackoftheorcs_v1_1.py相同的目錄中专缠。

接下來雷酪,更新attackoftheorcs_v1_1.py文件以包含以下更改:

首先,在文件的開頭添加以下import語句:

from gameuniterror import GameUnitError

第二個變化是在AbstractGameUnit.heal方法中藤肢。更新后的代碼顯示在以下代碼段中太闺。觀察高亮代碼,只要提出的價值自定義異常self.health_meter超過的self.max_hp嘁圈。

image

通過這兩個更改,運行之前創(chuàng)建的heal_exception_example.py蟀淮。您將看到引發(fā)新的異常最住,如以下屏幕截圖所示:

image

擴展異常類


我們可以用GameUnitError類做更多的事情嗎?當然怠惶!就像任何其他類一樣涨缚,我們可以定義屬性并使用它們。讓我們進一步擴展這個課程策治。在修改后的版本中脓魏,它將接受一個額外的參數(shù)和一些預(yù)定義的錯誤代碼。更新的GameUnitError類顯示在以下屏幕截圖中:

image

我們來看看前面屏幕截圖中的代碼:

· 首先通惫,它調(diào)用Exception超類的init方法茂翔,然后定義一些額外的實例變量。

· 一個新的dictionary對象self履腋。error_dict將錯誤整數(shù)代碼和錯誤信息保存為鍵值對珊燎。

· 該self.error_message存儲有關(guān)根據(jù)提供的錯誤代碼當前錯誤的信息。

· 在嘗試......除了子句確保error_dict實際上已經(jīng)由指定的鍵碼的說法遵湖。它不在except子句中悔政,我們只是檢索默認錯誤代碼為000的值。

image

到目前為止延旧,我們已經(jīng)對GameUnitError類和AbstractGameUnit.heal方法進行了更改谋国。我們還沒有完成。拼圖的最后一塊是修改主要在程序heal_exception_example.py文件迁沫。代碼顯示在以下屏幕截圖中:

image

我們來看看代碼:

· 由于heal_by值太大芦瘾,try子句中的heal方法會引發(fā)GameUnitError異常捌蚊。

· new except子句處理GameUnitError異常,就像任何其他內(nèi)置異常一樣旅急。

· 在except子句中逢勾,我們有兩個print語句。第一個打印health_meter> max_hpC晁薄(回想一下溺拱,當在heal方法中引發(fā)此異常時,此字符串被作為GameUnitError實例的第一個參數(shù)給出)谣辞。第二個print語句檢索并打印GameUnitError實例的error_message屬性迫摔。

我們已經(jīng)做好了所有的改變。我們可以在終端窗口中運行此示例:

$ python heal_exception_example.py

該程序的輸出顯示在以下屏幕截圖中:

image

在這個簡單的例子中泥从,將錯誤信息打印到控制臺句占。您可以進一步將詳細錯誤日志寫入文件,并跟蹤應(yīng)用程序運行時生成的所有錯誤消息躯嫉。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纱烘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子祈餐,更是在濱河造成了極大的恐慌擂啥,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件帆阳,死亡現(xiàn)場離奇詭異哺壶,居然都是意外死亡,警方通過查閱死者的電腦和手機蜒谤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門山宾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鳍徽,你說我怎么就攤上這事资锰。” “怎么了旬盯?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵台妆,是天一觀的道長。 經(jīng)常有香客問我胖翰,道長接剩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任萨咳,我火速辦了婚禮懊缺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己鹃两,他們只是感情好遗座,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著俊扳,像睡著了一般途蒋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上馋记,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天号坡,我揣著相機與錄音,去河邊找鬼梯醒。 笑死宽堆,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的茸习。 我是一名探鬼主播畜隶,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼号胚!你這毒婦竟也來了籽慢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤猫胁,失蹤者是張志新(化名)和其女友劉穎嗡综,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體杜漠,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年察净,在試婚紗的時候發(fā)現(xiàn)自己被綠了驾茴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡氢卡,死狀恐怖锈至,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情译秦,我是刑警寧澤峡捡,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站筑悴,受9級特大地震影響们拙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜阁吝,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一砚婆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧突勇,春花似錦装盯、人聲如沸坷虑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽迄损。三九已至,卻和暖如春账磺,著一層夾襖步出監(jiān)牢的瞬間芹敌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工绑谣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留党窜,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓借宵,卻偏偏與公主長得像幌衣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子壤玫,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

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

  • 用完美的表情 為脆弱的感情而撐著 劉濤說豁护,三十歲前你不娶她,她也不想嫁你了欲间,你以后遇到的都是壞女孩楚里。 闞清子說,過...
    冬天不會冷aaaa閱讀 505評論 0 0
  • 他鄉(xiāng)沉舊夢猎贴,濁酒醒殘年 對月苦含笑班缎,無人知暖寒
    游游俠閱讀 101評論 0 2
  • 1、人的磨難是很多的她渴,所以我們不可對於每一件輕微的傷害都過於敏感达址,在生活磨難面前,是一場無休趁耗、無歇沉唠、無情的戰(zhàn)鬥,凡...
    智囊團閱讀 166評論 0 0
  • 1. 喜歡一個人嘀韧,會去拼命了解,慢慢接近儡遮;愛上一個人乳蛾,會開心會難過、會吃醋會撒嬌,慢慢抵觸肃叶;愛過一個人蹂随,會長大會成...
    半粒苦澀半粒糖閱讀 493評論 0 0