ExceptionGroup是Python 3.11引入的继承BaseException的第一等异常对象,非语法糖;它以异常树根节点形式封装多个并发异常,需用except*解包匹配子异常,不可当列表操作,且add_note()仅作用于外层。

ExceptionGroup 不是“同时捕获多个异常”的语法糖,而是把多个异常打包成一个可抛出、可捕获、可传播的**第一等异常对象**。它能“同时处理多个错误”,本质是因为它被设计为异常树的根节点,而不是多个 except 块的替代品。
ExceptionGroup 是异常,不是列表或元组
你不能 raise [ValueError("a"), TypeError("b")],Python 会报 TypeError: exceptions must derive from BaseException。但你可以:
raise ExceptionGroup("batch failed", [ValueError("a"), TypeError("b")])
这是因为 ExceptionGroup 继承自 BaseException,和 ValueError 平级,是合法的异常类型。它内部用 exceptions 属性存子异常(tuple),但这个 tuple 不可变,也不自动展开——你得显式访问或用 except* 拆解。
- 误当成 list 处理:直接遍历
e会报错,必须遍历e.exceptions - 误用
str(e)查看内容:只显示顶层消息和数量,看不到各子异常 traceback - 老版本 Python 直接运行会报
NameError: name 'ExceptionGroup' is not defined,它不是向后兼容的“特性”,而是 3.11+ 的原生类型
except* 才是专为 ExceptionGroup 设计的匹配机制
except ValueError: 匹配的是单个 ValueError 实例;except Exception: 匹配所有继承自 Exception 的异常,但 ExceptionGroup 继承自 BaseException,不在此列。真正能精准分流子异常的,只有 except*:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
-
except* ValueError as eg:→eg.exceptions里只含匹配上的ValueError实例(可能 0 个、1 个或多个) - 多个
except*块按顺序执行,未被前一个捕获的子异常会留给下一个继续尝试 - 没被任何
except*捕获的子异常,最终仍会冒泡,不会静默丢弃 - 不能和普通
except混用在同一个try块里;要么全用except*,要么退回到显式except ExceptionGroup:
并发场景下 ExceptionGroup 是怎么产生的
它不是手动构造出来的“玩具”,而是 asyncio 或线程池在真实失败时自动组装的:
-
asyncio.gather(a(), b(), c(), return_exceptions=False)遇到多个协程失败 → 自动 raiseExceptionGroup -
return_exceptions=True时返回结果列表,需手动过滤isinstance(r, BaseException)再构造,漏掉这步就得不到多异常流 -
concurrent.futures.ThreadPoolExecutor.map()出错时不会自动产生ExceptionGroup,得自己包装 -
asyncio.TaskGroup(3.11+)在with块退出时,若多个任务失败,也自动 raiseExceptionGroup
最易被忽略的一点:ExceptionGroup 的 add_note() 只作用于自身消息,不影响其 exceptions 中任意子异常的 note 或 traceback——每个子异常的上下文是独立保留的,这点对调试和错误追踪至关重要。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










