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