python自定义异常应继承exception而非baseexception;类名须以error结尾,构造参数仅保留message、code、details等必要字段;仅对非预期错误抛异常,避免滥用。

Python 自定义异常该继承哪个基类
直接继承 Exception,别用 BaseException(除非你真在写解释器或信号拦截)。绝大多数业务异常必须是 Exception 的子类,否则会被 except: 捕获但绕过常规错误处理流程,比如日志、监控、重试逻辑全失效。
常见错误现象:
- 自定义异常没被上层
try/except Exception:捕获(实际捕获了但没进分支) - 单元测试里
assertRaises(YourError)失败,但手动抛却能触发
使用场景:
- 需要被业务层统一兜底(如 API 视图层 catch 所有
Exception并转 HTTP 400) - 要兼容现有中间件(Django 的
process_exception、FastAPI 的exception_handlers)
注意:
立即学习“Python免费学习笔记(深入)”;
- 不要继承
SystemExit、KeyboardInterrupt这类退出类异常 - 若需区分“可恢复”和“不可恢复”,靠命名和文档,别靠继承链深度
异常类名和构造参数怎么设计才不翻车
异常类名必须以 Error 结尾(如 UserNotFoundError),这是 Python 社区事实标准,IDE、linter(如 pylint)、traceback 解析工具都依赖这个约定。类名要体现“什么错了”,而不是“哪里错的”。
构造参数只保留必要上下文:
- 必须有
message(字符串),用于日志和用户提示 - 可选
code(整数或字符串),供下游做机器判断(如前端跳转不同错误页) - 可选
details(字典),存结构化调试信息(如字段名、原始值),但别塞大对象或函数
反例:
DouPHP模块化企业网站管理系统是一款轻量级企业网站管理系统,基于PHP+MYSQL架构的,包含“手机版”、“公众号管理模块”、“小程序”,可以使用它快速搭建一个企业网站。 DouPHP功能特色: (模块全部免费,一键安装) 功能性模块:防伪查询模块、投票模块、自定义表单模块、工单模块等、会员模块、订单模块、视频模块、下载模块、图片模块等; 企业官网模块:业务范围
-
class UserError(Exception):→ 名称太泛,无法区分是创建失败还是查询失败 -
def <strong>init</strong>(self, user_obj, request_id):→user_obj可能不可序列化,打日志时直接崩溃
示例:
class OrderPaymentFailedError(Exception):
def __init__(self, order_id: str, reason: str, code: str = "PAYMENT_FAILED"):
self.order_id = order_id
self.code = code
self.details = {"reason": reason}
super().__init__(f"Payment failed for order {order_id}: {reason}")
什么时候该抛异常,什么时候该返回 None 或 False
明确区分“异常条件”和“预期分支”:
- 用户提交邮箱格式错误 → 抛
ValidationError(非预期输入) - 查询数据库没找到用户 → 抛
UserNotFoundError(业务上不该发生) - 缓存未命中 → 返回
None(完全预期) - 第三方 API 限流 → 抛
RateLimitExceededError(需重试或降级)
容易踩的坑:
- 把“找不到资源”当正常流,结果上层逻辑空指针崩溃
- 在工具函数里抛业务异常(如
format_phone()抛UserNotFoundError),污染调用栈 - 用异常控制普通流程(如用
KeyError判断字典是否存在键),性能差且语义错
记住:异常用于“出事了,当前路径走不下去”,不是“换个方式继续”。
日志、监控和 traceback 里怎么让自定义异常真正有用
异常实例必须自带可读 message,且不能依赖 <strong>str</strong> 动态拼接(因为某些日志框架只取 args[0])。所有关键字段(如 ID、状态码)必须显式传入 super().<strong>init</strong>(),否则 traceback 里看不到。
监控告警依赖 <strong>class</strong>.<strong>name</strong>,所以:
- 类名别缩写(
URLErr❌,URLError✅) - 同一模块内避免相似名(
UserError和UserAuthError容易混淆)
性能影响:
- 不要在异常
<strong>init</strong>里做 I/O、网络请求或复杂计算 - 避免在异常中存大对象引用(如整个 request 对象),会拖慢 GC,还可能泄露内存
一个常被忽略的点:如果你的异常类带额外属性(如 self.code),确保它能在 unpickle 时重建——很多分布式任务框架(Celery、Ray)会序列化异常,属性丢失会导致 traceback 信息残缺。








