Python异常处理需按子类到父类顺序排列except块,避免宽泛类型前置;可用元组捕获多异常,3.11+支持ExceptionGroup并发多异常处理,禁用空except和sys.exc_info()动态分发。

用多个 except 块分别处理不同异常类型
Python 支持按异常类型逐层匹配,越具体的异常越要放在前面。如果把 Exception 这种宽泛类型写在前面,后面的特定异常(比如 ValueError)根本不会被执行到。
常见错误现象:except Exception: 写在 except ValueError: 上面,导致所有异常都被兜底捕获,调试时看不到具体错误原因。
- 顺序必须是:子类异常在前,父类异常在后(如
ValueError→Exception) - 每个
except块可以单独处理逻辑,比如记录日志、重试、转换为自定义错误 - 不建议只写
except:(空 except),它会吞掉KeyboardInterrupt和SystemExit,导致程序无法正常中断
try:
int("abc")
1 / 0
except ValueError as e:
print(f"转数字失败:{e}")
except ZeroDivisionError as e:
print(f"除零错误:{e}")
except Exception as e:
print(f"其他异常:{type(e).__name__}: {e}")用元组在单个 except 中捕获多个异常类型
当多个异常需要执行完全相同的处理逻辑时,用元组比重复写多个 except 更简洁。注意括号不能省——except ValueError, TypeError: 是旧 Python 2 写法,现在会把 TypeError 当作变量名,引发语法错误。
使用场景:读文件时可能遇到 FileNotFoundError 或 PermissionError,都统一提示“文件不可访问”。
立即学习“Python免费学习笔记(深入)”;
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
- 元组中类型顺序无关,但必须是实际存在的异常类(不能是字符串)
- 不能在元组里混用异常类和字符串,例如
except (ValueError, "not found"):会报SyntaxError - 这种写法适合“同质化处理”,不适合需要差异化响应的场景
try:
with open("missing.txt") as f:
f.read()
except (FileNotFoundError, PermissionError) as e:
print(f"文件访问失败:{e}")用 exceptiongroup(Python 3.11+)处理并发任务中的多异常
当用 asyncio.gather() 或 concurrent.futures 并发执行多个操作时,可能同时抛出多个异常。老版本 Python 只能捕获第一个,而 ExceptionGroup 把它们打包成一个可迭代的异常容器。
容易踩的坑:直接 except Exception: 会错过 ExceptionGroup,必须显式捕获或用 except*(PEP 654 新语法)。
-
except* ValueError:匹配组内所有ValueError实例,返回新的ExceptionGroup - 未被
except*捕获的异常仍保留在原组中,最终会重新抛出 - 低于 3.11 的环境需用第三方库
exceptiongroup(pip install exceptiongroup)并手动导入
import asyncio
<p>async def maybe_fail(n):
if n == 2:
raise ValueError("n is 2")
if n == 3:
raise TypeError("n is 3")
return n * 10</p><p>async def main():
try:
await asyncio.gather(maybe_fail(1), maybe_fail(2), maybe_fail(3))
except<em> ValueError as eg:
print(f"捕获到 {len(eg.exceptions)} 个 ValueError")
except</em> TypeError as eg:
print(f"捕获到 {len(eg.exceptions)} 个 TypeError")</p><h1>Python 3.11+ 才能运行为什么不要依赖 sys.exc_info() 做异常分发
有人想在单个 except Exception: 里用 sys.exc_info() 判断类型再分支处理,这不仅冗余,还绕过了 Python 异常匹配机制的语义优势——比如丢失了异常上下文链(__cause__ / __context__),也增加出错概率。
性能影响:sys.exc_info() 调用本身开销不大,但手动做类型判断会让代码更难维护,且无法享受 IDE 对 except 块的静态分析支持。
- 真正需要动态分发的场景极少,多数时候是设计问题(比如封装了不透明的黑盒函数)
- 若必须动态处理,请用
isinstance(e, (ValueError, TypeError)),而不是字符串匹配type(e).__name__ - 记住:异常类型是第一公民,不是事后补救的数据字段
最常被忽略的一点:except 块里再抛异常时,用 raise(无参数)保留原始 traceback;用 raise new_exc from e 显式建立因果链——否则调试时会丢掉关键上下文。

















