现代 Python 中如何正确定义自定义异常?
Python 自定义异常的标准做法是继承 Exception(或更具体的内置异常类),按需添加属性。本文给出规范写法、继承选择与常见误区。
标准做法:定义一个继承自 Exception 的新类,在 __init__ 中保存自定义属性。如果语义合适,优先继承更具体的内置异常(如 ValueError),调用方可以用更宽泛或更精确的 except 捕获。
基本写法
class MyException(Exception):
def __init__(self, message):
self.message = message
super().__init__(message)
raise MyException("这是我的自定义异常")
调用 super().__init__(message) 是个好习惯:保证 str(exc)、args 等标准行为正常工作。
选择合适的基类
class InvalidConfigError(ValueError):
"""配置值非法时抛出"""
继承具体异常的好处:调用方原有的 except ValueError 依然能捕获它,向后兼容。
项目级异常体系
常见模式是定义一个项目基类,再派生具体异常:
class AppError(Exception):
"""本项目所有异常的基类"""
class DatabaseError(AppError):
pass
class ConfigError(AppError):
pass
这样调用方可以 except AppError 一网打尽,也可以精确捕获子类。
常见问题(FAQ)
Q:能从 BaseException 继承吗?
A:不要。BaseException 是 KeyboardInterrupt、SystemExit 的基类,继承它会导致异常被 except Exception 漏捕,破坏常规错误处理逻辑。
Q:自定义异常需要实现 str 吗?
A:一般不需要。把信息传给 Exception.__init__ 就有默认的字符串表示;只有想定制展示格式时才重写。
Q:异常信息很多怎么办?
A:在 __init__ 中接收多个参数存为属性(如 self.code、self.payload),捕获方可以读取这些属性做结构化处理,比往 message 字符串里塞信息更可维护。