<p>ExceptionGroup 彻底改变了异步并发中错误传播的底层契约,强制处理多个异常同时发生的情况;它继承自 BaseException 而非 Exception,因此 except Exception 无法捕获,必须使用 except* 或 except BaseException 显式解包处理。</p>

ExceptionGroup 不是“让异常更好看”的语法糖,而是彻底改变了异步并发中错误传播的底层契约:它强制你面对“多个异常同时发生”这个事实,而不是继续假装只有一个。
asyncio.gather 里抛出的异常突然不被捕获了
升级到 Python 3.11 后,原来能 catch 住的 asyncio.gather() 异常,现在静默跳过——不是代码坏了,是 ExceptionGroup 根本不是 Exception 的子类。旧写法 except Exception: 对它完全无效。
- 现象:日志没报错、监控无告警、HTTP 返回 500,但 traceback 里找不到源头
- 原因:
asyncio.gather(return_exceptions=False)在多任务失败时,自动封装成ExceptionGroup抛出,而ExceptionGroup继承自BaseException,绕过了所有except Exception: - 修复不是改一行,而是必须显式处理:
except* ValueError:或兜底用except BaseException:
except* 不是可选语法糖,是唯一能解包 ExceptionGroup 的方式
普通 except 捕获不到 ExceptionGroup 里的单个子异常;只有 except* 能按类型批量提取、分类、计数。
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
-
except* httpx.HTTPStatusError as eg:——eg.exceptions是列表,每个元素都是原始的httpx.HTTPStatusError实例 - 不能写
except ExceptionGroup:,因为它是内置类型,没有导出为顶层名称;必须用except* ...:或except BaseException: - 嵌套场景下(比如子任务又抛出
ExceptionGroup),except*会递归匹配所有层级的匹配异常,不用手动展开
不处理 ExceptionGroup 会导致资源泄漏和静默降级
异常被吞掉不是“程序没崩”,而是协程提前退出、清理逻辑跳过、连接/锁/文件句柄全卡在中间状态——这是 SRE 真实事故的起点。
立即学习“Python免费学习笔记(深入)”;
- 典型链路:一个
aiohttp.ClientSession被某个任务提前 close,其他还在跑的任务直接抛RuntimeError: <client> is closed</client> - 根本问题:旧式
try/except拦不住ExceptionGroup,导致整个async with块提前终止,__aexit__不执行 - 最轻量补救:在入口注册
sys.excepthook,用exceptiongroup库(兼容 3.9+)递归打印所有子异常,至少让日志可见
真正难的不是写对 except*,而是意识到:以前靠“运气”没出事的并发代码,现在只要有两个任务同时失败,就暴露出资源管理漏洞——这恰恰是 ExceptionGroup 想逼你正视的事。


















