7.1 創建自定義例外
有時候,Python 的預設例外無法完全滿足你應用程序的需求。在這種情況下,你可以通過繼承基類 Exception
或其他合適的例外類來創建自己的例外。
創建自定義例外的基礎
創建自定義例外包括定義一個新的類,這個類繼承自基類 Exception
。你可以在例外類中添加自己的方法和屬性,以提供更多的錯誤信息。
簡單自定義例外的示例
步驟1:定義自定義例外
class MyCustomError(Exception):
"""自定義例外的類。"""
pass
步驟2:使用自定義例外
def check_value(value):
if value < 0:
raise MyCustomError("值不應該小於零")
try:
check_value(-1)
except MyCustomError as e:
print(f"發生了自定義例外: {e}")
這非常簡單。關鍵是你的例外需要繼承自 Exception
類或它的子類。
7.2 創建帶有附加屬性的例外
你可以在你的例外類中添加屬性和方法,以傳遞更多有關錯誤的信息。
示例:
class NegativeValueError( Exception ):
"""當值為負時,自定義例外的類。"""
def __init__(self, value, message = "值不應該小於零"):
self.value = value
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.value}'
使用帶有附加屬性的例外
def check_value(value):
if value < 0:
raise NegativeValueError(value)
try:
check_value(-1)
except NegativeValueError as e:
print(f"發生了自定義例外: {e}")
我們的例外是從 Exception
類繼承的類。因此,您可以像對任何其他類一樣對它進行操作:添加字段、方法、構造函數參數等。
這一切都是為了您的方便,以及將要處理您的例外的程序員的方便。
7.3 創建自定義例外的層次結構
對於更複雜的應用程序,創建自定義例外的層次結構是有用的。它允許你將相關的例外分組,並簡化它們的處理。
示例:
class ApplicationError(Exception):
"""應用程序所有例外的基礎類。"""
pass
class NegativeValueError(ApplicationError):
"""當值為負時,自定義例外的類。"""
def __init__(self, value, message="值不應該小於零"):
self.value = value
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.value}'
class ValueTooLargeError(ApplicationError):
"""當值太大時,自定義例外的類。"""
def __init__(self, value, message="值太大"):
self.value = value
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.value}'
使用自定義例外的層次結構
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except NegativeValueError as e:
print(f"發生了例外: {e}")
except ValueTooLargeError as e:
print(f"發生了例外: {e}")
except ApplicationError as e:
print(f"應用程序通用例外: {e}")
7.4 捕獲例外的順序
捕獲例外時,尤其是同一層次結構中的例外時,指定它們的正確順序很重要。雖然 except
塊中的代碼不會同時執行,但事實是基礎例外類能夠捕捉所有子類的例外。
例如,代碼:
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except ApplicationError as e: # 捕捉類型為 ApplicationError 及其所有子類的例外
print(f"應用程序通用例外: {e}")
在 except
塊中,將捕捉類型為 ApplicationError
及其所有子類的例外。
由於所有的例外都是從 Exception
類繼承的,所以這樣的代碼將捕捉到所有的例外:
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except Exception as e:
print(f"捕捉所有例外: {e}")
except ApplicationError as e: # 此代碼永遠不會執行
print(f"應用程序通用例外: {e}")
在 except ApplicationError
塊中捕捉例外的永遠不會發生,因為 except Exception
塊將捕捉所有類型為 Exception
的例外及其子類。
解決方案
因此,例外捕捉的順序應該是與繼承相反的:離 Exception
類越近的類越低。
示例:
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except NegativeValueError as e:
print(f"發生了例外: {e}")
except ApplicationError as e:
print(f"應用程序通用例外: {e}")
except Exception as e:
print(f"捕捉所有例外: {e}")
在這個示例中,except
塊的順序與它們的繼承結構相對應:首先捕捉更具體的例外,例如 NegativeValueError
,然後是更泛型的,如 ApplicationError
。這樣可以正確處理例外,避免當更普遍的處理程序在更專門的 except
塊有機會處理之前捕捉到例外。
GO TO FULL VERSION