应定义具体异常类型而非直接 raise exception,如 ordervalidationerror、insufficientstockerror 等继承 exception;按类型捕获可精准处理,避免字符串匹配;异常类应携带结构化字段(如 order_id)便于诊断,且字段名变更属破坏性修改。

为什么直接 raise Exception() 会让后续排查变困难
业务代码里随手写 raise Exception("订单金额异常"),短期能跑通,但调用方无法区分这是参数校验失败、库存不足,还是支付网关超时。没有类型信息,就没办法用 except 精准捕获,只能靠字符串匹配或宽泛的 Exception,一出错就得翻日志逐行看堆栈。
自定义异常类必须继承 BaseException 的子类
Python 要求所有异常都得是 BaseException 的后代,但实际开发中应继承 Exception(而非直接继承 BaseException),否则会拦截 KeyboardInterrupt 或 SystemExit 这类系统级中断,导致程序无法被 Ctrl+C 正常终止。
常见错误写法:class OrderError(BaseException): pass —— 这会让 sys.exit() 失效。
正确做法:
class OrderValidationError(Exception):
pass
<p>class InsufficientStockError(Exception):
pass</p><p>class PaymentTimeoutError(Exception):
pass</p>
在 except 中按类型捕获比检查字符串更可靠
当异常带明确类型,上层就能做差异化处理:比如 OrderValidationError 返回 400 给前端,PaymentTimeoutError 则自动重试,InsufficientStockError 触发缺货通知。
- 错误方式:
except Exception as e: if "库存" in str(e): ...—— 字符串易变,测试难覆盖 - 正确方式:
except InsufficientStockError as e:—— 类型稳定,IDE 可跳转,mypy 能静态检查 - 可叠加使用:多个异常类型写成元组,
except (OrderValidationError, PaymentTimeoutError) as e:
给异常加字段比只传 message 更利于诊断
业务异常往往需要附带上下文,比如订单 ID、用户 ID、失败时间戳。光靠 str(e) 解析既脆弱又低效。
推荐写法:
class OrderValidationError(Exception):
def __init__(self, order_id: str, field: str, value: str):
self.order_id = order_id
self.field = field
self.value = value
super().__init__(f"Order {order_id}: invalid {field}='{value}'")
<h1>使用</h1><p>raise OrderValidationError("ORD-789", "amount", "-100")</p>
这样调用方可以直接访问 e.order_id 记录日志或上报监控,不用再从 message 里正则提取。
注意:不要在 __str__ 里拼接敏感字段(如用户手机号),避免误打到公开日志中。
异常类一旦上线,字段名和类型就构成契约——改字段名等于破坏兼容性,这点容易被忽略。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











