Python 3.12未降低异常开销,try/except和raise成本基本不变;改进仅限ExceptionGroup与except*的并发异常处理语义,非性能优化。

Python 3.12 并没有引入“改进的异常处理机制”来降低开销——恰恰相反,try/except 块本身的运行时开销在 3.12 中与之前版本基本一致,且异常抛出(raise)仍是高成本操作。所谓“改进”,实际仅体现在 ExceptionGroup 和 except* 的语义增强上,它们解决的是并发异常聚合问题,而非性能优化。
Python 3.12 的 except* 不减少开销,只改变捕获逻辑
except* 是为处理 ExceptionGroup 设计的,它匹配子异常并拆包,但每次匹配仍需遍历异常树、构造新 ExceptionGroup 实例。它不跳过异常对象创建,也不绕过栈展开——所以对单个异常场景完全无加速作用。
常见误用现象:有人把 except* 当作更“轻量”的 except,结果发现代码变慢了,尤其在未触发异常的热路径上,except* 的语法解析和类型检查开销略高于传统 except。
- 仅在
asyncio.gather(..., return_exceptions=True)或threading.Thread批量任务后处理多个并发异常时才应使用except* - 不要用
except* ValueError:替代except ValueError:——前者在单异常下多做一次分组判断,纯属负优化 -
except*捕获后返回的仍是ExceptionGroup(哪怕只剩一个子异常),需显式调用exc.exceptions[0]取出原异常,否则容易漏掉上下文
真正能降低异常开销的做法:避免抛异常
Python 异常开销主要来自三部分:栈帧捕获、 traceback 对象构建、异常对象初始化。3.12 没有优化这些环节。降低开销的核心策略仍是“别让异常发生”:
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
立即学习“Python免费学习笔记(深入)”;
- 用
dict.get(key, default)替代dict[key]+KeyError捕获 - 用
hasattr(obj, 'attr')或getattr(obj, 'attr', sentinel)替代try/except AttributeError - 对已知可能失败的 I/O 操作(如
os.path.exists),优先做预检而非依赖OSError捕获 - 在循环内避免重复抛异常——例如校验列表元素时,先用
all()或生成器表达式预筛,而不是逐个try
3.12 中唯一与异常开销相关的底层变化:__suppress_context__ 默认为 True(仅影响显示)
Python 3.12 将 BaseException.__suppress_context__ 的默认值从 False 改为 True,但这只影响 traceback 输出是否显示 During handling of the above exception... 链式提示,完全不影响异常创建、抛出或捕获的 CPU/内存开销。
这个改动容易引发误解:有人看到错误信息变短了,就以为“异常变快了”。实际只是 print(exc) 时省了两行字符串拼接,对性能无实质意义。
- 若需恢复旧版链式提示(调试需要),手动设
exc.__suppress_context__ = False - 该字段不影响
sys.excepthook行为,也不改变logging.exception()的输出内容 - 自定义异常类若重写了
__init__但没调用super().__init__(),可能意外覆盖此默认值,导致 traceback 显示异常
真正影响异常开销的,从来不是语法糖或显示逻辑,而是你是否在热路径里把控制流交给 raise。3.12 没给这条老路铺新砖,只是加了条岔道去管一群异常——而那条岔道本身并不比主路快。

















