except*是Python 3.11引入的专用于捕获ExceptionGroup中匹配子集异常的语法,不能捕获单个异常;它从异常组中筛选指定类型异常并构造成新ExceptionGroup绑定变量,未匹配异常保留在原组中供后续处理。

except* 是什么,和普通 except 有什么根本区别
except* 是 Python 3.11 引入的语法,专用于处理 异常组(ExceptionGroup)——也就是一次抛出多个不相关异常的情况,比如 asyncio.gather(..., return_exceptions=False) 遇到多个任务失败,或手动用 ExceptionGroup("msg", [exc1, exc2]) 构造。它不是普通 except 的增强版,不能替代单异常捕获;写成 except* ValueError: 去抓一个单独的 ValueError 会直接报 SyntaxError: invalid syntax。
常见错误现象:
– 在非异常组上下文中使用 except*
– 混淆 except* 和 except 的触发条件
– 忘记 except* 分支只匹配“该类型异常在异常组中的子集”,而非整个组
如何正确触发并进入 except* 分支
必须确保 try 块中实际抛出的是 ExceptionGroup(或其子类),且其中至少有一个异常实例匹配 except* 后声明的类型。Python 不会自动把多个独立 raise 合并成组——得靠 except 中重新聚合成组,或用支持异常组的并发原语。
- ✅ 正确方式:用
asyncio.gather(..., return_exceptions=False)并让 ≥2 个协程分别 raise 不同异常 - ✅ 手动构造:
raise ExceptionGroup("batch", [ValueError("a"), TypeError("b")]) - ❌ 错误方式:
raise ValueError(); raise TypeError()(只会执行第一个,第二个永不触发) - ❌ 错误方式:在同步代码里只抛一个
ValueError,却写except* ValueError:
except* 中匹配部分异常的实操要点
except* 的核心行为是“提取匹配的异常子集”:它会从当前 ExceptionGroup 中筛选出所有属于指定类型的异常(包括子类),打包成一个新的 ExceptionGroup 绑定到变量;未匹配的异常仍留在原组中,供后续 except* 分支继续处理。
示例:
try:
raise ExceptionGroup("op failed", [
ValueError("bad input"),
TypeError("wrong type"),
ValueError("missing field")
])
except* ValueError as eg:
print(f"捕获 {len(eg.exceptions)} 个 ValueError:{[str(e) for e in eg.exceptions]}")
except* TypeError as eg:
print(f"捕获 {len(eg.exceptions)} 个 TypeError")
输出:捕获 2 个 ValueError:['bad input', 'missing field']捕获 1 个 TypeError
注意:
– eg 是新的 ExceptionGroup,不是列表,不能用 eg[0] 直接索引(要用 eg.exceptions[0])
– 同一 except* 分支无法同时捕获 ValueError 和 TypeError,必须分开写两个分支
– 如果所有异常都不匹配任何 except*,原始 ExceptionGroup 会向上冒泡
容易被忽略的兼容性与调试陷阱
Python 3.11+ 才支持 except*,旧版本运行会直接 SyntaxError;而且目前标准库中只有少数地方原生返回异常组(如 asyncio.gather、taskgroup.create_task),多数第三方库还没适配。调试时容易误判:看到 ExceptionGroup 实例但没意识到它必须由 except* 处理,而试图用普通 except Exception: 捕获——结果发现进不去分支,因为 ExceptionGroup 不是 Exception 的子类(它是平行于 BaseException 的新分支)。
关键点:
– isinstance(exc, Exception) 对 ExceptionGroup 返回 False
– 想兜底捕获所有异常(含异常组),必须显式写 except* BaseException: 或 except (Exception, ExceptionGroup):
– 日志打印 ExceptionGroup 时默认只显示第一层,需调用 eg.print_exception() 查看完整嵌套结构










