python 3.11+ 中 asyncio.gather() 抛出 exceptiongroup 需显式捕获,用 except exceptiongroup: 处理;return_exceptions=true 时不抛异常,结果中混有异常对象;嵌套时需递归展开;except* 是专为 exceptiongroup 设计的新语法。

asyncio.gather() 抛出 ExceptionGroup 时怎么捕获
Python 3.11 中 asyncio.gather() 在多个协程出错时不再只抛最上面一个异常,而是打包成 ExceptionGroup。直接用 except Exception: 捕不到——它不是 Exception 的子类,而是并列关系。
正确做法是显式捕获 ExceptionGroup,再用 exceptions 属性或 exceptiongroup.ExceptionGroup.split() 拆解:
import asyncio
from exceptiongroup import ExceptionGroup
<p>async def fails():
raise ValueError("boom")</p><p>async def main():
try:
await asyncio.gather(fails(), fails(), return_exceptions=False)
except ExceptionGroup as eg:
for e in eg.exceptions:
print(f"caught: {type(e).<strong>name</strong>}: {e}")
</p>
注意:Python 3.11+ 已内置 ExceptionGroup,无需额外安装 exceptiongroup 包;但若需在 3.11 以下兼容,才需 pip install。
return_exceptions=True 时还用不用处理 ExceptionGroup
用 return_exceptions=True 后,gather() 不再抛异常,而是把异常对象作为结果列表中的元素返回。此时不会生成 ExceptionGroup,你拿到的是混着 ValueError、TypeError 等具体异常实例的 list。
所以这种模式下不需要处理 ExceptionGroup,但得自己遍历结果、用 isinstance(x, BaseException) 判断哪些是异常:
- 别直接
str(x)或print(x)—— 未处理的异常对象可能触发隐式 traceback - 推荐先过滤:
[x for x in results if isinstance(x, BaseException)] - 如果只关心某类错误(比如仅重试网络错误),可针对性检查
isinstance(x, ConnectionError)
asyncio.create_task() + wait_for 组合引发的嵌套 ExceptionGroup
当对单个带超时的 task 使用 asyncio.wait_for(),而该 task 内部又用 gather() 并发执行多个子任务时,异常堆叠会形成嵌套 ExceptionGroup:外层是 TimeoutError(来自 wait_for),内层才是真正的业务异常组。
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
这时 except ExceptionGroup: 只能捕到最外层,容易漏掉真实根因。稳妥做法是递归展开:
def flatten_exception_group(eg):
if not isinstance(eg, ExceptionGroup):
return [eg]
flat = []
for e in eg.exceptions:
flat.extend(flatten_exception_group(e))
return flat
<h1>...</h1><p>except ExceptionGroup as eg:
for e in flatten_exception_group(eg):
if isinstance(e, ValueError):
handle_value_error(e)
</p>
不建议依赖 eg.subgroup()——它只按类型筛选,无法穿透多层嵌套。
和传统 try/except 块混用时的常见陷阱
在 async 函数里写 try...except ValueError:,同时又期望捕获 gather() 抛出的 ExceptionGroup,这种写法会失败:因为 ExceptionGroup 不是 ValueError,也不会被其父类 Exception 捕获(除非显式写 except (Exception, ExceptionGroup):)。
真正安全的顶层异常捕获模式是:
-
except ExceptionGroup as eg:—— 处理并发异常 -
except* ValueError as eg:—— Python 3.11 新语法,专为ExceptionGroup设计,自动匹配子异常中所有ValueError实例(包括嵌套) -
except BaseException as be:—— 最宽泛,但慎用,会吞掉KeyboardInterrupt和SystemExit
最容易被忽略的一点:except* 不能和普通 except 混在同一个 try 块里——语法报错。必须分开写,或者统一用 except* 覆盖全部并发场景。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










