Skip to main content

Python: errors

📅 2026-03-31 ✏️ 2026-03-31 CS PYTHON
No related notes

1 · Python: Errors and Exceptions#

https://docs.python.org/3/tutorial/errors.html

Python有两类错误:语法错误(解析期)和异常(运行期)。

1.1 · 异常层级

BaseException           # 所有异常的根基类
├── SystemExit          # sys.exit()
├── KeyboardInterrupt   # Ctrl+C
├── GeneratorExit       # generator.close()
└── Exception           # 所有"常规"异常的基类(捕获时通常用这个)
    ├── ValueError
    ├── TypeError
    ├── OSError
    │   └── FileNotFoundError
    ├── RuntimeError
    │   └── RecursionError
    ├── StopIteration
    ├── ExceptionGroup   # 3.11+
    └── ...

except Exception 能捕获几乎所有异常,但不捕获 SystemExit/KeyboardInterrupt/GeneratorExit

1.2 · 捕获异常 try/except#

执行流:

  1. 执行 try 子句
  2. 无异常 → 跳过 except → 执行 else → 执行 finally
  3. 有异常 → 匹配第一个 except → 执行 finally;无匹配则 finally 后 re-raise

except 匹配规则:匹配异常是该类或其子类的实例。 先写子类、后写父类。

try:
    x = int(input("number: "))
except ValueError:                 # 捕获特定异常
    print("invalid")
except (TypeError, OSError) as e:  # 多个异常 + 绑定实例
    print(e)
except Exception as e:             # 兜底(捕获后应 re-raise 或记录)
    print(f"Unexpected {e=}, {type(e)=}")
    raise
else:                              # try 没有异常时执行(避免意外捕获)
    print("success")
finally:                           # 无论如何都执行(清理资源)
    print("cleanup")

finally 的陷阱

  • finally 中的 return吞掉异常和 try 的返回值(3.14 起发 SyntaxWarningPEP 765
  • finally 中的 break/continue 同理会阻止异常 re-raise

1.3 · 抛出异常 raise#

raise ValueError("bad value")       # 抛出异常实例
raise ValueError                    # 等价于 raise ValueError()
raise                               # re-raise 当前异常(保留原始traceback)

1.4 · 异常链 Exception Chaining#

# 显式链:raise ... from exc → __cause__
try:
    connect()
except ConnectionError as exc:
    raise RuntimeError("DB failed") from exc
# traceback: "The above exception was the direct cause of ..."

# 隐式链:except 中 raise 新异常 → __context__(自动附加)
# traceback: "During handling of the above exception, another exception occurred ..."

# 禁用链:from None
raise RuntimeError("clean msg") from None

1.5 · 自定义异常

约定:命名以 Error 结尾;继承 Exception(不是 BaseException)。

class AppError(Exception):
    """应用基础异常"""

class NotFoundError(AppError):
    def __init__(self, resource: str, id: str):
        self.resource = resource
        self.id = id
        super().__init__(f"{resource} {id} not found")

1.6 · with 语句(预定义清理)#

优于 try/finally 手动关闭;实现了上下文管理器协议 (__enter__/__exit__) 的对象都可用。

with open("file.txt") as f:    # __enter__ / __exit__ 协议
    data = f.read()
# 无论是否异常,f 都会被关闭

1.7 · ExceptionGroup 与 except* (3.11+)#

并发场景下多个任务可能同时失败,需要同时报告多个异常。

# 创建
raise ExceptionGroup("problems", [OSError("e1"), ValueError("e2")])

# 捕获:except* 按类型从 group 中选择性提取
try:
    ...
except* OSError as eg:      # eg 是只含 OSError 的子 ExceptionGroup
    handle_os(eg.exceptions)
except* ValueError as eg:
    handle_val(eg.exceptions)
# 未匹配的异常会继续 re-raise

1.8 · add_note (3.11+)#

常见用法:在 ExceptionGroup 中为每个子异常附加上下文信息(如迭代序号)。

try:
    raise TypeError("bad type")
except Exception as e:
    e.add_note("additional context")  # 追加到 __notes__ 列表
    raise
# traceback 末尾显示 notes

1.9 · 与 Go 错误处理的对比#

维度PythonGo
机制异常(抛出/捕获,控制流跳转)值(返回/检查,显式控制流)
传播自动沿调用栈向上传播手动 return err
多错误ExceptionGroup + except*errors.Join
封装raise ... from exc(异常链)fmt.Errorf("%w", err)
清理with/finallydefer
穷举无编译期保证(同Go)无编译期保证

异常与值的核心区别在于控制流

  • 异常是隐式传播、显式捕获(抛出后自动沿调用栈上跳,不捕获则崩溃)
  • 值是显式传播、显式检查(留在当前调用点,不处理则静默吞掉)