使用Python進行異常處理

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

本文閱讀時長:10min

本文所涉及知識點

  • Python中有哪些異常 ?

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

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

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

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

什么是異常?


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

在早期回溯中看到的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習如何使用try ... except子句來處理這些異常。以下偽代碼顯示了try ... except子句的一個非常簡單的示例:

image

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

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

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

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

這里使用的 except子句是通用的。它將捕獲try子句中發(fā)生的所有類型的異常。而不是擁有這個“全能”處理程序,更好的做法是捕獲您預期的錯誤并編寫特定于這些錯誤的異常處理代碼。例如,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,這會導致NameError。此異常由另一個異常子句處理,但NameError除外。同樣,您可以為預期的錯誤定義特定的異常處理程序。

提高并重新提出異常


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ā)異常。假設,在try子句中,您有一個將數(shù)字除以零的表達式。在普通算術(shù)中,這個表達沒有意義。這是一個錯誤!這會導致程序引發(fā)一個名為ZeroDivisionError的異常。如果沒有異常處理代碼,程序?qū)⒅淮蛴″e誤消息并終止。

如果您希望將此錯誤寫入某個日志文件然后終止該程序,該怎么辦?在這里,您可以使用except子句首先記錄錯誤。然后,使用不帶任何參數(shù)的raise關(guān)鍵字來重新引發(fā)異常。異常將在堆棧中向上傳播。在此示例中,它終止程序??梢允褂胷aise關(guān)鍵字重新引發(fā)異常而不使用任何參數(shù)。

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

image

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

image

try ... except


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

image

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

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í)行清理任務。示例用例是關(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類復制到其自己的模塊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ù)和一些預定義的錯誤代碼。更新的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_hp?。ɑ叵胍幌拢斣趆eal方法中引發(fā)此異常時,此字符串被作為GameUnitError實例的第一個參數(shù)給出)。第二個print語句檢索并打印GameUnitError實例的error_message屬性。

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

$ python heal_exception_example.py

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

image

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容