一、为什么需要自定义异常?
自定义异常可以让你的代码更清晰地表达特定的错误情况,提供更有意义的错误信息,并实现更精细的错误处理。
二、基础自定义异常
1. 最简单的自定义异常
# 最简单的自定义异常class MyError(Exception): """我的自定义异常""" pass# 使用示例def test_simple_error(): try: raise MyError("发生了一个错误") except MyError as e: print(f"捕获到自定义异常: {e}")test_simple_error()
2. 带初始化的自定义异常
class ValidationError(Exception): """验证错误异常""" def __init__(self, message, field_name=None, code=None): self.field_name = field_name self.code = code # 调用父类构造函数 super().__init__(message)# 使用示例def validate_user(name, age): if not name: raise ValidationError("姓名不能为空", field_name="name", code="REQUIRED") if age < 0: raise ValidationError("年龄不能为负数", field_name="age", code="INVALID_RANGE") if age > 150: raise ValidationError("年龄超出范围", field_name="age", code="OUT_OF_RANGE")try: validate_user("", 25)except ValidationError as e: print(f"错误: {e}") print(f"字段: {e.field_name}") print(f"错误码: {e.code}")
三、自定义异常的层次结构
1. 创建异常层次
# 定义异常层次class AppError(Exception): """应用基础异常""" passclass DatabaseError(AppError): """数据库错误""" passclass ConnectionError(DatabaseError): """连接错误""" passclass QueryError(DatabaseError): """查询错误""" passclass BusinessError(AppError): """业务逻辑错误""" passclass ValidationError(BusinessError): """验证错误""" passclass AuthorizationError(BusinessError): """授权错误""" pass# 使用示例def test_hierarchy(): def db_operation(): raise ConnectionError("无法连接到数据库") def business_logic(): raise ValidationError("数据验证失败") try: db_operation() except ConnectionError as e: print(f"连接错误: {e}") except DatabaseError as e: print(f"数据库错误: {e}") except AppError as e: print(f"应用错误: {e}") try: business_logic() except ValidationError as e: print(f"验证错误: {e}") except BusinessError as e: print(f"业务错误: {e}")test_hierarchy()
2. 多级异常处理
class APIError(Exception): """API 错误基类""" passclass ClientError(APIError): """客户端错误 (4xx)""" def __init__(self, message, status_code=400): self.status_code = status_code super().__init__(message)class ServerError(APIError): """服务器错误 (5xx)""" def __init__(self, message, status_code=500): self.status_code = status_code super().__init__(message)class NotFoundError(ClientError): """资源不存在 (404)""" def __init__(self, resource, resource_id): self.resource = resource self.resource_id = resource_id message = f"{resource} 不存在: {resource_id}" super().__init__(message, status_code=404)class UnauthorizedError(ClientError): """未授权错误 (401)""" def __init__(self, message="需要认证"): super().__init__(message, status_code=401)# 使用示例def test_api_errors(): def get_user(user_id): if user_id == 0: raise UnauthorizedError() if user_id != 123: raise NotFoundError("User", user_id) return {"id": user_id, "name": "Alice"} user_ids = [0, 999, 123] for user_id in user_ids: try: user = get_user(user_id) print(f"获取用户成功: {user}") except UnauthorizedError as e: print(f"认证错误 ({e.status_code}): {e}") except NotFoundError as e: print(f"未找到 ({e.status_code}): {e}") except ClientError as e: print(f"客户端错误 ({e.status_code}): {e}") except APIError as e: print(f"API错误: {e}")test_api_errors()
四、最佳实践
1. 异常设计原则
class ExceptionDesignPrinciples: """异常设计原则""" # 1. 继承自 Exception 而不是 BaseException class GoodException(Exception): pass # 2. 提供有意义的错误信息 class UserNotFoundError(Exception): def __init__(self, user_id): super().__init__(f"用户不存在: {user_id}") self.user_id = user_id # 3. 保持异常层次合理 class AppError(Exception): pass class DatabaseError(AppError): pass class ValidationError(AppError): pass # 4. 不要滥用自定义异常 # 如果内置异常足够,优先使用内置异常 # 5. 文档化异常 def divide(a, b): """ 除法运算 Raises: ZeroDivisionError: 当除数为0时 TypeError: 当参数不是数字时 """ return a / b # 6. 异常应该是可序列化的 class SerializableError(Exception): def __init__(self, message, code=None): super().__init__(message) self.code = code def to_dict(self): return { 'type': self.__class__.__name__, 'message': str(self), 'code': self.code } print("异常设计原则演示完成")
2. 自定义异常模板
class ExceptionTemplate: """自定义异常模板""" # 模板1: 简单异常 class SimpleError(Exception): """简单错误""" pass # 模板2: 带数据的异常 class DataError(Exception): def __init__(self, message, **kwargs): self.data = kwargs super().__init__(message) def __str__(self): if self.data: return f"{super().__str__()}{self.data}" return super().__str__() # 模板3: 错误码异常 class CodeError(Exception): def __init__(self, message, code=500): self.code = code super().__init__(f"[{code}] {message}") # 模板4: 异常链异常 class ChainedError(Exception): def __init__(self, message, cause=None): self.cause = cause if cause: message = f"{message} (cause: {cause})" super().__init__(message) # 模板5: 上下文异常 class ContextError(Exception): def __init__(self, message, context=None): self.context = context or {} super().__init__(message) def with_context(self, key, value): self.context[key] = value return self# 使用模板def test_templates(): try: raise ExceptionTemplate.SimpleError("简单错误") except ExceptionTemplate.SimpleError as e: print(f"简单异常: {e}") try: raise ExceptionTemplate.DataError("数据错误", user_id=123, action="delete") except ExceptionTemplate.DataError as e: print(f"数据异常: {e}") try: raise ExceptionTemplate.CodeError("权限不足", code=403) except ExceptionTemplate.CodeError as e: print(f"错误码异常: {e}") try: try: raise ValueError("原始错误") except ValueError as e: raise ExceptionTemplate.ChainedError("包装后的错误", cause=e) except ExceptionTemplate.ChainedError as e: print(f"链式异常: {e}")test_templates()
五、总结
自定义异常要点表格
| |
|---|
| 继承基类 | 通常继承 Exception,不要继承 BaseException |
| 构造函数 | 调用 super().__init__() 传递错误消息 |
| 额外属性 | |
| 异常层次 | |
| 文档化 | |
最佳实践总结
命名规范:异常类名应以 Error 结尾
继承关系:创建合理的异常层次结构
提供信息:包含足够的调试信息
文档化:说明异常的触发条件
不要滥用:优先使用内置异常
可序列化:便于日志和传输
自定义异常是 Python 编程中的重要技巧,合理使用可以让代码更清晰、更易维护。通过创建有意义的异常层次和提供丰富的错误信息,可以大大提高程序的健壮性和可调试性。