Python異常類(lèi)型的使用及說(shuō)明
在Python中,我們可以 raise
的 Error(更準(zhǔn)確地說(shuō)是 Exception,異常)類(lèi)型非常豐富,它們構(gòu)成了一個(gè)清晰的類(lèi)層次結(jié)構(gòu)。了解這些類(lèi)型及其用途,對(duì)于編寫(xiě)健壯、可讀性強(qiáng)的代碼至關(guān)重要。
NotImplementedError
是一個(gè)非常好的例子,它代表了一種特定的“設(shè)計(jì)意圖”,而不僅僅是運(yùn)行時(shí)錯(cuò)誤。
下面我將為您詳細(xì)介紹Python中可以 raise
的主要異常類(lèi)型,并按照它們的邏輯關(guān)系和用途進(jìn)行分類(lèi)。
一、異常的基本層次結(jié)構(gòu)
所有Python的內(nèi)置異常都繼承自 BaseException
類(lèi)。這個(gè)層次結(jié)構(gòu)非常重要:
BaseException ├── SystemExit ├── KeyboardInterrupt └── Exception <-- 絕大多數(shù)異常都繼承自這里 ├── StopIteration ├── ArithmeticError │ ├── ZeroDivisionError │ └── OverflowError ├── AssertionError ├── AttributeError ├── ImportError │ └── ModuleNotFoundError ├── LookupError │ ├── IndexError │ └── KeyError ├── NameError ├── OSError │ ├── FileNotFoundError │ └── PermissionError ├── RuntimeError │ └── NotImplementedError <-- 你提到的在這里 ├── TypeError ├── ValueError └── ...等等
一條黃金法則:
在你的 try...except
語(yǔ)句中,通常應(yīng)該捕獲 Exception
或其子類(lèi),而不是 BaseException
。因?yàn)?SystemExit
和 KeyboardInterrupt
不被認(rèn)為是程序“錯(cuò)誤”,捕獲它們會(huì)阻止程序正常退出或響應(yīng)用戶(hù)中斷(Ctrl+C)。
二、主要異常類(lèi)型詳解
我將它們分為幾類(lèi),以便更好地理解它們的用途。
類(lèi)別1:最常見(jiàn)的運(yùn)行時(shí)錯(cuò)誤
這些是你在日常編程中遇到最多的錯(cuò)誤。
ValueError
- 何時(shí)使用:當(dāng)一個(gè)函數(shù)的參數(shù)類(lèi)型正確,但其值不合適時(shí)。
- 示例:
int('abc')
。字符串'abc'
是一個(gè)str
類(lèi)型,int()
可以接受str
,但'abc'
這個(gè)值無(wú)法被轉(zhuǎn)換成整數(shù)。
TypeError
- 何時(shí)使用:當(dāng)對(duì)一個(gè)對(duì)象執(zhí)行了其類(lèi)型不支持的操作時(shí)。
- 示例:
'hello' + 5
。你不能將一個(gè)字符串和一個(gè)整數(shù)相加。
NameError
- 何時(shí)使用:當(dāng)嘗試使用一個(gè)未被定義的變量名時(shí)。
- 示例:
print(my_undefined_variable)
。
IndexError
- 何時(shí)使用:當(dāng)試圖訪問(wèn)序列(如列表、元組)中一個(gè)不存在的索引時(shí)。
- 示例:
my_list = [1, 2, 3]; print(my_list[5])
。
KeyError
- 何時(shí)使用:當(dāng)試圖訪問(wèn)字典中一個(gè)不存在的鍵時(shí)。
- 示例:
my_dict = {'a': 1}; print(my_dict['b'])
。
AttributeError
- 何時(shí)使用:當(dāng)試圖訪問(wèn)或賦值一個(gè)對(duì)象不存在的屬性或方法時(shí)。
- 示例:
my_int = 5; my_int.append(6)
。整數(shù)沒(méi)有append
方法。
類(lèi)別2:用于程序設(shè)計(jì)和邏輯控制的異常
這類(lèi)異常通常由程序員主動(dòng) raise
,以表明某種設(shè)計(jì)上的約定或狀態(tài)。
NotImplementedError
(繼承自 RuntimeError
)
- 何時(shí)使用:在父類(lèi)(尤其是抽象基類(lèi))中定義一個(gè)方法,并強(qiáng)制要求所有子類(lèi)必須重寫(xiě)(實(shí)現(xiàn))這個(gè)方法。它清楚地告訴其他開(kāi)發(fā)者:“這個(gè)功能需要你自己去實(shí)現(xiàn)”。
示例:
class Shape: def get_area(self): # 任何繼承自Shape的子類(lèi)都必須實(shí)現(xiàn)自己的get_area方法 raise NotImplementedError("Subclasses must implement this method!") class Square(Shape): def __init__(self, side): self.side = side # 如果不寫(xiě)下面的方法,調(diào)用 get_area() 就會(huì)報(bào)錯(cuò) def get_area(self): return self.side ** 2 # s = Shape() # s.get_area() # 這會(huì)立即引發(fā) NotImplementedError sq = Square(5) print(sq.get_area()) # 輸出 25
AssertionError
- 何時(shí)使用:當(dāng)
assert
語(yǔ)句的條件為False
時(shí)被觸發(fā)。它主要用于內(nèi)部自檢和調(diào)試,檢查程序在某個(gè)點(diǎn)的狀態(tài)是否符合預(yù)期。它不應(yīng)該用于驗(yàn)證用戶(hù)輸入。
示例:
def process_data(data): assert isinstance(data, list), "Input data must be a list" # ... 后續(xù)處理 ... process_data("not a list") # 引發(fā) AssertionError: Input data must be a list
RuntimeError
- 何時(shí)使用:當(dāng)發(fā)生一個(gè)不屬于任何其他明確類(lèi)別的錯(cuò)誤時(shí)。它是一個(gè)比較通用的錯(cuò)誤,通常表示發(fā)生了某些意想不到的外部事件。
NotImplementedError
就是它的一個(gè)子類(lèi)。
類(lèi)別3:與外部環(huán)境交互的錯(cuò)誤
OSError
- 何時(shí)使用:當(dāng)發(fā)生系統(tǒng)相關(guān)的錯(cuò)誤時(shí),例如I/O操作失敗。它是一個(gè)廣泛的基類(lèi)。
它的重要子類(lèi)包括:
FileNotFoundError
: 試圖打開(kāi)一個(gè)不存在的文件。open('non_existent_file.txt')
。PermissionError
: 試圖以沒(méi)有權(quán)限的方式讀寫(xiě)文件。例如,試圖寫(xiě)入一個(gè)只讀文件。ConnectionError
: 與網(wǎng)絡(luò)連接相關(guān)的問(wèn)題,如連接被拒絕 (ConnectionRefusedError
)。TimeoutError
: 一個(gè)操作在指定時(shí)間內(nèi)未能完成。
類(lèi)別4:算術(shù)和導(dǎo)入錯(cuò)誤
ArithmeticError
- 何時(shí)使用:所有數(shù)值計(jì)算錯(cuò)誤的基類(lèi)。
子類(lèi)包括:
ZeroDivisionError
: 除以零。1 / 0
。OverflowError
: 計(jì)算結(jié)果超出了數(shù)字類(lèi)型能表示的最大范圍。import math; math.exp(1000)
。
ImportError
- 何時(shí)使用:當(dāng)
import
語(yǔ)句無(wú)法找到或加載模塊時(shí)。 ModuleNotFoundError
(自 Python 3.6 起):是ImportError
的一個(gè)子類(lèi),更明確地表示模塊本身未找到。- 示例:
import some_module_that_does_not_exist
。
類(lèi)別5:語(yǔ)法錯(cuò)誤(特殊情況)
SyntaxError
- 何時(shí)發(fā)生:這是你在運(yùn)行代碼之前就會(huì)遇到的錯(cuò)誤。Python解釋器在解析代碼時(shí)發(fā)現(xiàn)語(yǔ)法不正確。你不能在
try...except
塊中捕獲它,因?yàn)樗诖a執(zhí)行前就失敗了。 IndentationError
(子類(lèi)):最常見(jiàn)的語(yǔ)法錯(cuò)誤之一,代碼縮進(jìn)不正確。
三、創(chuàng)建你自己的自定義異常
當(dāng)內(nèi)置的異常類(lèi)型無(wú)法精確描述你的應(yīng)用程序特有的錯(cuò)誤時(shí),最佳實(shí)踐是創(chuàng)建自己的異常類(lèi)。這能讓你的代碼更具可讀性和可維護(hù)性。
自定義異常應(yīng)該繼承自 Exception
或其某個(gè)合適的子類(lèi)。
示例:假設(shè)你在開(kāi)發(fā)一個(gè)與外部API交互的應(yīng)用。
# 1. 創(chuàng)建一個(gè)基礎(chǔ)的自定義異常類(lèi) class MyAppError(Exception): """應(yīng)用程序所有自定義異常的基類(lèi)。""" pass # 2. 創(chuàng)建更具體的異常類(lèi) class APIResponseError(MyAppError): """當(dāng)API返回一個(gè)意外的或錯(cuò)誤的響應(yīng)時(shí)引發(fā)。""" def __init__(self, message, status_code): super().__init__(message) self.status_code = status_code # 3. 在代碼中使用它 def get_user_data(user_id): # response = requests.get(f"https://api.example.com/users/{user_id}") # 模擬一個(gè)失敗的響應(yīng) status_code = 500 if status_code != 200: raise APIResponseError(f"Failed to fetch data, API returned {status_code}", status_code) # return response.json() # 4. 捕獲它 try: get_user_data(123) except APIResponseError as e: print(f"Error communicating with API: {e}") print(f"Status code was: {e.status_code}") except MyAppError as e: print(f"An application-specific error occurred: {e}")
總結(jié)
使用 內(nèi)置異常 來(lái)表示通用的編程錯(cuò)誤(如 ValueError
, TypeError
)。
使用 NotImplementedError
來(lái)定義接口和抽象方法,強(qiáng)制子類(lèi)實(shí)現(xiàn)。
使用 AssertionError
進(jìn)行內(nèi)部調(diào)試和狀態(tài)檢查。
當(dāng)內(nèi)置異常不足以描述你的特定問(wèn)題域時(shí),創(chuàng)建自定義異常,以提高代碼的清晰度和健壯性。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
利用python實(shí)現(xiàn)你說(shuō)我猜游戲的完整實(shí)例
這篇文章主要給大家介紹了關(guān)于如何利用python實(shí)現(xiàn)你說(shuō)我猜游戲的相關(guān)資料,用到的都是一些簡(jiǎn)單的基礎(chǔ)的python語(yǔ)句,適合剛?cè)腴T(mén)的小白,可以嘗試跟著一起敲一下,感受一下編程中的樂(lè)趣,需要的朋友可以參考下2022-05-05python數(shù)據(jù)結(jié)構(gòu)之搜索講解
這篇文章主要介紹了python數(shù)據(jù)結(jié)構(gòu)之搜索講解,搜索是指從元素集合中找到某個(gè)特定元素的算法過(guò)程。搜索過(guò)程通常返回?True?或?False,?分別表示元素是否存在,下面一起來(lái)了解文章的詳細(xì)內(nèi)容吧,希望對(duì)你有所幫助2021-12-12pycharm中keras導(dǎo)入報(bào)錯(cuò)無(wú)法自動(dòng)補(bǔ)全cannot?find?reference分析
這篇文章主要介紹了pycharm中keras導(dǎo)入報(bào)錯(cuò)無(wú)法自動(dòng)補(bǔ)全cannot?find?reference分析,文章圍繞主題展開(kāi)分析,需要的小伙伴可以參考一下2022-07-07Python使用Phantomjs截屏網(wǎng)頁(yè)的方法
今天小編就為大家分享一篇Python使用Phantomjs截屏網(wǎng)頁(yè)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05關(guān)于Python 多重繼承時(shí)metaclass conflict問(wèn)題解決與原理探究
這篇文章主要介紹了Python 多重繼承時(shí)metaclass conflict問(wèn)題解決與原理探究 ,需要的朋友可以參考下2022-10-10Python減少循環(huán)層次和縮進(jìn)的技巧分析
這篇文章主要介紹了Python減少循環(huán)層次和縮進(jìn)的技巧,結(jié)合實(shí)例形式較為詳細(xì)的分析了Python優(yōu)化代碼跳出循環(huán)以減少循環(huán)層次的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-03-03Python解決多線程運(yùn)行異步代碼報(bào)錯(cuò)"There?is?no?current?event?loop
在Python開(kāi)發(fā)中,我們經(jīng)常需要同時(shí)處理高并發(fā)網(wǎng)絡(luò)請(qǐng)求和CPU密集型任務(wù),不過(guò)當(dāng)嘗試在多線程環(huán)境中運(yùn)行異步代碼時(shí),可能會(huì)報(bào)錯(cuò)"There?is?no?current?event?loop",下面我們看看具體的解決方法吧2025-04-04詳解在python操作數(shù)據(jù)庫(kù)中游標(biāo)的使用方法
這篇文章主要介紹了在python操作數(shù)據(jù)庫(kù)中游標(biāo)的使用方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-11-11