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

