- 來源 | 愿碼(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解釋器并編寫以下代碼:
以下是一些異常情況:
正如您所看到的,代碼的每一行都會拋出一個帶有異常類型的錯誤回溯(突出顯示)贡珊。這些是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子句的一個非常簡單的示例:
我們來看看前面的代碼片段:
· 首先判帮,程序嘗試執(zhí)行try子句中的代碼局嘁。
· 在執(zhí)行期間,如果出現(xiàn)錯誤(如果發(fā)生異常)晦墙,它將跳出此try子句悦昵。try塊中的其余代碼不會被執(zhí)行。
· 然后晌畅,它在except子句中查找適當?shù)漠惓L幚沓绦虿?zhí)行它但指。
這里使用的 except子句是通用的。它將捕獲try子句中發(fā)生的所有類型的異常抗楔。而不是擁有這個“全能”處理程序棋凳,更好的做法是捕獲您預(yù)期的錯誤并編寫特定于這些錯誤的異常處理代碼。例如连躏,try子句中的代碼可能會拋出AssertionError剩岳。您可以編寫特定的異常處理程序,而不是使用universal except子句入热,如下所示:
在這里拍棕,我們有一個except子句專門處理AssertionError晓铆。它還意味著除了AssertionError之外的任何錯誤都將作為未處理的異常漏掉。為此绰播,我們需要使用不同的異常處理程序定義多個except子句骄噪。但是,在任何時候幅垮,只會調(diào)用一個異常處理程序腰池。用一個例子可以更好地解釋這一點。我們來看看下面的代碼片段:
該試塊調(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ā)異常:
可以看出,在解決a / b表達式時旋圆,會出現(xiàn)zeroexception的adivision宠默。這是因為變量b的值設(shè)置為0。出于說明目的灵巧,我們假設(shè)此錯誤沒有特定的異常處理程序搀矫。因此,我們將使用general except子句刻肄,在記錄錯誤后重新引發(fā)異常瓤球。如果您想自己嘗試,只需在新的Python文件中編寫前面說明的代碼敏弃,然后從終端窗口運行它卦羡。以下屏幕截圖顯示了上述代碼的輸出:
try ... except
可以在try ... except子句中指定可選的else塊。在其他的只發(fā)生ifno異常塊被執(zhí)行的嘗試......除了條款权她。語法如下:
在其他塊的前執(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塊的運行情況:
運行這個簡單的代碼將產(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í)行炒瘟。
在最后條款通常用于離開功能之前執(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嘁圈。
通過這兩個更改,運行之前創(chuàng)建的heal_exception_example.py蟀淮。您將看到引發(fā)新的異常最住,如以下屏幕截圖所示:
擴展異常類
我們可以用GameUnitError類做更多的事情嗎?當然怠惶!就像任何其他類一樣涨缚,我們可以定義屬性并使用它們。讓我們進一步擴展這個課程策治。在修改后的版本中脓魏,它將接受一個額外的參數(shù)和一些預(yù)定義的錯誤代碼。更新的GameUnitError類顯示在以下屏幕截圖中:
我們來看看前面屏幕截圖中的代碼:
· 首先通惫,它調(diào)用Exception超類的init方法茂翔,然后定義一些額外的實例變量。
· 一個新的dictionary對象self履腋。error_dict將錯誤整數(shù)代碼和錯誤信息保存為鍵值對珊燎。
· 該self.error_message存儲有關(guān)根據(jù)提供的錯誤代碼當前錯誤的信息。
· 在嘗試......除了子句確保error_dict實際上已經(jīng)由指定的鍵碼的說法遵湖。它不在except子句中悔政,我們只是檢索默認錯誤代碼為000的值。
到目前為止延旧,我們已經(jīng)對GameUnitError類和AbstractGameUnit.heal方法進行了更改谋国。我們還沒有完成。拼圖的最后一塊是修改主要在程序heal_exception_example.py文件迁沫。代碼顯示在以下屏幕截圖中:
我們來看看代碼:
· 由于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
該程序的輸出顯示在以下屏幕截圖中:
在這個簡單的例子中泥从,將錯誤信息打印到控制臺句占。您可以進一步將詳細錯誤日志寫入文件,并跟蹤應(yīng)用程序運行時生成的所有錯誤消息躯嫉。