<p>except* 是专为捕获 ExceptionGroup 中多个子异常设计的语法,能“拆包”匹配子异常类型;普通 except 只匹配单个异常实例,无法处理 ExceptionGroup。</p>

什么是 except*,它和普通 except 有什么本质区别
except* 不是增强版的单异常捕获,而是专为「同时抛出多个异常」的场景设计的语法,核心解决的是 asyncio.gather(..., return_exceptions=False) 或 taskgroup.create_task() 中任务组(TaskGroup)里多个子任务各自失败时的聚合异常处理问题。普通 except 遇到 ExceptionGroup 会直接跳过——它只匹配单个异常实例,而 except* 能从 ExceptionGroup 中“拆包”并匹配其中符合类型的子异常。
关键点:只有当异常对象是 ExceptionGroup(或其子类,如 BaseExceptionGroup)时,except* 才会生效;普通 ValueError 抛出来,except* ValueError 是捕获不到的。
在 asyncio.TaskGroup 中必须用 except* 捕获多任务异常
Python 3.11 引入 asyncio.TaskGroup 作为 asyncio.gather 的替代方案,它的设计原则是“任一子任务失败即中止全部”,且把所有已发生的异常打包成 ExceptionGroup 向上抛出。此时若用传统 except ValueError:,会完全漏掉错误。
- 正确写法必须用
except* ValueError:或except* ConnectionError:等具体类型 - 可以叠加多个
except*分支,各自处理不同异常类型(顺序无关,全部匹配) - 未被任何
except*匹配的子异常,会保留在剩余的ExceptionGroup中,最终仍会重新抛出 - 如果想捕获全部子异常,用
except* BaseException:(但慎用,可能掩盖致命错误)
import asyncio
<p>async def maybe_fail(n):
if n == 2:
raise ValueError("failed at 2")
if n == 3:
raise RuntimeError("failed at 3")
return f"ok {n}"</p><p>async def main():
try:
async with asyncio.TaskGroup() as tg:
tg.create_task(maybe_fail(1))
tg.create_task(maybe_fail(2))
tg.create_task(maybe_fail(3))
except<em> ValueError as eg:
print(f"ValueErrors: {len(eg.exceptions)}") # → 1
except</em> RuntimeError as eg:
print(f"Runtimes: {len(eg.exceptions)}") # → 1
except* 的匹配行为与常见踩坑点
except* 不是“捕获一个就停”,而是对 ExceptionGroup 内每个子异常独立尝试匹配——哪怕同一个 except* 分支也会被触发多次(只要对应类型出现多次)。但它不会递归展开嵌套的 ExceptionGroup,只处理直接子异常。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
立即学习“Python免费学习笔记(深入)”;
- 错误示范:
except* Exception:→ 实际上几乎没用,因为ExceptionGroup本身不是Exception的实例,它继承自BaseException;应改用except* BaseException:(但更推荐精确类型) - 混淆点:不能在非
ExceptionGroup上用except*,比如普通函数里raise ValueError,外面写except* ValueError会直接报SyntaxError(解释器拒绝解析) - 调试技巧:打印
eg.exceptions是元组,可遍历查看每个原始异常的__traceback__和args - 注意
return_exceptions=True的gather不会产生ExceptionGroup,所以不适用except*
何时该坚持用传统 except,而不是强行上 except*
except* 只在明确知道上游会抛 ExceptionGroup 时才有意义。大多数同步代码、单任务 await、或手动构造的异常,都不涉及该机制。
- Web 框架中间件、普通 API 视图函数里,异常仍是单个抛出,继续用
except ValueError: - 单元测试中模拟多异常?别自己造
ExceptionGroup,除非你真在测TaskGroup行为 - 误以为“多个
except可以捕获多个异常”——不行,那是误解;单次raise只能抛一个异常对象,不管它是不是ExceptionGroup - 跨 Python 版本兼容性:3.11+ 才支持
except*,旧版本需降级为except ExceptionGroup as eg:+ 手动遍历eg.exceptions
真正需要 except* 的地方其实很窄:就是你主动用了 asyncio.TaskGroup 或显式调用了 exceptiongroup.ExceptionGroup 的时候。其他情况加了也没用,还让代码变难读。

















