前几天在掘金看到一篇文章 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

小结

遵循这三条原则可以让异常处理更可控、更清晰:尽量只捕获必要的异常、在抽象边界做转换、并保持业务逻辑主导权。