必须用 except 捕获 ExceptionGroup,否则并发异常会漏掉;asyncio.gather() 默认将多个异常打包为 ExceptionGroup 抛出,仅 except Exception 或 except* 具体类型可安全捕获并筛选子异常。

必须用 except* 捕获 ExceptionGroup,否则几乎所有并发异常都会漏掉——哪怕你写了 except Exception: 也完全无效。
asyncio.gather() 默认就抛 ExceptionGroup
Python 3.11+ 中,asyncio.gather(a(), b(), c()) 只要任意一个协程出错(哪怕只有一个),就会把所有已发生的异常打包成 ExceptionGroup 抛出。这不是可选行为,是默认机制。
-
except ValueError:→ 不匹配,因为ExceptionGroup和ValueError是平行类型,不继承 -
except Exception:→ 不匹配,因为ExceptionGroup继承自BaseException,而非Exception -
except BaseException:→ 能捕获,但会吞掉KeyboardInterrupt、SystemExit等信号,生产环境禁用 - 正确写法只有:
except* ValueError as eg:或except* Exception as eg:
except* 不是“捕获一次”,而是“筛选子异常”
except* 的本质是遍历 eg.exceptions 元组里的每个原始异常,把类型匹配的挑出来,组成一个新的 ExceptionGroup 绑定给 eg。
-
eg.exceptions是 tuple,不是 list,不可修改;每个元素是原始异常实例,含完整 traceback - 多个
except*块按顺序执行:前一个没匹配上的子异常,后一个还能继续捕获 -
except* (TimeoutError, ConnectionError) as eg:合法,等价于两个独立的except* - 如果所有
except*都没覆盖某个子异常,它仍会向上冒泡,不会静默丢弃
TaskGroup 内部异常必须用 except*,不能靠 await 后 try-except
async with asyncio.TaskGroup() as tg: 里多个任务失败时,await 语句只会抛第一个异常,其余被取消且异常被静默丢弃——除非你用 except*。
立即学习“Python免费学习笔记(深入)”;
- 写
except ValueError:完全捕不到其他任务的TypeError或OSError -
except* Exception as eg:是兜底最简写法,能拿到全部原始异常 - 想分别处理:用
except* TimeoutError as eg:+except* ValueError as eg:分开响应 - 打印全部细节请用
traceback.print_exception(eg);str(eg)只显示摘要,比如"2 exceptions"
低版本 Python(
如果你卡在 Python 3.10 或更早,ExceptionGroup 和 except* 都不存在,import exceptiongroup 第三方包也只解决构造,不解决语法支持。
- 替代方案:用
asyncio.gather(..., return_exceptions=True),结果列表中混着Exception实例和正常返回值 - 必须手动遍历结果,用
isinstance(x, BaseException)过滤异常,再raise x或记录 -
TaskGroup在低版本根本不存在,只能用asyncio.create_task()+ 显式await+ 单个try-except,无法真正“统一捕获多异常” - 升级到 3.11+ 是唯一能获得结构化并发错误流的方式;降级方案本质是把异常处理逻辑从语言层移到业务层,更易出错
最容易被忽略的是:ExceptionGroup 不会自动展开,eg.exceptions 必须显式遍历,且每个子异常的 traceback 是独立保留的——不调用 traceback.print_exception(eg) 或逐个 traceback.print_exception(e),你就永远看不到完整上下文。


















