前几天在掘金看到一篇文章 Python 工匠:异常处理的三个好习惯,文章提出三条核心建议:
- 只做最精确的异常捕获;
- 别让异常破坏抽象一致性;
- 异常处理不应该喧宾夺主。
下面逐条说明要点并给出示例。
只做最精确的异常捕获
目标是不捕获不必要的异常,避免掩盖真正的问题。
精确包含两方面:
- 捕获精确:把 try 的范围缩小到仅包含可能抛出异常的语句;
- 类型精确:在 except 中使用尽可能具体的异常类型。
这样能让代码更安全、更易排查。
别让异常破坏抽象一致性
保持模块在其抽象层级内抛出一致的异常,有利于统一处理和集中定义错误信息。实践要点:
- 模块只抛出与当前抽象层级一致的异常;
- 在边界处进行必要的异常包装或转换(例如 requests 对 urllib3 的封装)。
这样调用方只需捕获少量高层次异常即可。
异常处理不应该喧宾夺主
异常处理应辅助业务逻辑,而不是充斥代码,使正常流程变得难以阅读。可用上下文管理器统一转换或包装异常,保持业务逻辑简洁。
示例:将指定异常捕获并替换为统一的错误码异常。
class raise_api_error:
"""捕获指定异常并抛出 ApiErrorCode(用于统一错误返回)。
:raises: AttributeError 如果 code_name 无效
"""
def __init__(self, captures, code_name):
self.captures = captures
self.code = getattr(error_codes, code_name)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
# 在退出上下文时被调用:exc_type, exc_val, exc_tb
if exc_type is None:
return False
if exc_type == self.captures:
raise self.code from exc_val
return False
小结
遵循这三条原则可以让异常处理更可控、更清晰:尽量只捕获必要的异常、在抽象边界做转换、并保持业务逻辑主导权。