add_note 方法只能在异常实例上直接调用,必须在异常抛出前或 except 块中对原始异常实例调用,note 为纯字符串、不参与匹配、仅影响 traceback 渲染,且 python ≤3.10 不支持。

add_note 方法只能在异常实例上直接调用,不能对已捕获但未抛出的异常对象“事后添加”
Python 3.11 引入的 add_note 是个实例方法,它只修改当前异常对象本身,不改变 traceback 结构,也不影响后续 raise 的行为。关键点在于:你必须在异常被抛出前、或在 except 块中对捕获到的异常实例调用它,且该异常尚未被重新抛出(否则原 traceback 会被覆盖)。
常见错误是试图对一个已经完成 traceback 渲染的异常(比如从 sys.exc_info() 拿到后又过了几层函数)再加 note —— 这能成功执行,但实际打印时往往看不到 note,因为 Python 只在最终未捕获异常的格式化阶段读取 __notes__ 属性,而此时原始异常可能已被包装或替换。
-
add_note必须作用于「同一个异常实例」,不是副本 - 如果用了
raise exc from ...或raise new_exc,原异常的 note 不会自动继承 - note 内容是纯字符串,不支持格式化占位符(得自己
f"..."拼好再传)
在 except 块中为捕获的异常追加上下文最可靠
这是 add_note 最典型也最安全的用法:你在处理异常时,知道缺失哪些现场信息(比如用户 ID、请求路径、配置值),就当场补上。
try:
risky_operation()
except ValueError as e:
e.add_note(f"User ID: {user_id}")
e.add_note(f"Config mode: {config.mode}")
raise # 重新抛出,note 会显示在 traceback 底部
注意:raise 后不带参数才能保留原始 traceback 和新增的 note;若写成 raise e,虽然也能工作,但某些调试器或日志框架可能因异常被显式重抛而忽略 __notes__。
- 多个
add_note调用会按顺序累积,最终显示为多行 note - note 不参与异常类型匹配(
except ValueError不受 note 影响) - 如果异常被多次捕获并多次
add_note,所有 note 都会保留在该实例上
add_note 对 traceback 输出的影响取决于 Python 版本和运行环境
Python 3.11+ 默认在未捕获异常的 traceback 末尾显示所有 __notes__,每行以 note: 开头;但在 IPython、Jupyter 或某些 IDE 中,note 可能被折叠、截断,甚至完全不显示——这跟它们如何解析 __traceback__ 和 __notes__ 有关。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
更隐蔽的问题是:如果你用 logging.exception() 记录异常,标准 logging 模块在 Python 3.12 之前**不会输出 note**,必须手动提取:
try:
...
except Exception as e:
e.add_note("DB connection timeout")
logger.error("Operation failed", exc_info=True)
# note 不会出现在日志里!需额外打印:
if hasattr(e, '__notes__') and e.__notes__:
logger.debug("Exception notes: %s", "\n".join(e.__notes__))
- note 不会出现在
repr(e)或str(e)中,只用于 traceback 渲染 -
traceback.format_exception()在 Python 3.12+ 才默认包含 note;旧版本需手动拼接 - pytest 等测试框架目前对 note 支持有限,失败输出里常看不到
替代方案:什么时候不该用 add_note?
当你需要结构化上下文(比如带 key 的 metadata)、跨层级传递、或兼容旧 Python 版本时,add_note 就不够用了。它只是字符串追加,没法做条件过滤、序列化或集成进监控系统。
例如,想把 user_id 注入所有下游异常,用 add_note 得每个 except 块都写一遍;而用 exception.__cause__ = ContextError(...) 或自定义异常基类 + __init__ 参数,反而更可控。
- note 无法被 except 捕获或检查(没有 API 读取特定 note)
- 不能用于抑制或修改异常逻辑,纯属诊断辅助
- 如果项目还要支持 Python ≤ 3.10,得 fallback 到
args += ("note: ...",)或自定义属性
真正容易被忽略的是:note 不是“异常元数据”的通用解决方案,它只解决“让 traceback 多打几行辅助文本”这一个具体问题。别的需求,得另找路子。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










