python异常清理需分层处理:显式按类型写except块区分清理逻辑,finally执行无条件清理,sys.exc_info()获取异常信息,上下文管理器封装类型相关清理。

捕获特定异常并执行对应清理动作
Python 的 except 语句支持按异常类型分层处理,这是实现“不同异常、不同清理”的基础。关键不是靠 try...except Exception: 一把抓,而是显式列出你关心的异常类,并为每种配一个独立的 except 块。
- 常见错误:把所有异常都塞进同一个
except,导致网络超时和文件权限错误走同一套清理逻辑,比如误删临时目录或重试已失败的连接 - 正确做法:按实际故障场景拆分,例如
ConnectionError触发重连清理,PermissionError记录权限日志但跳过资源释放 - 注意继承关系:
OSError是PermissionError和FileNotFoundError的父类,若先写except OSError:,后面的子类except就永远不会执行
在 finally 中统一执行非异常相关清理
finally 适合放那些“无论是否出错都必须做”的操作,比如关闭文件句柄、释放锁、还原全局状态。但它不适合区分异常类型——里面没法知道当前是哪种异常触发了退出。
- 典型场景:打开文件后读取数据,不管成功还是抛
UnicodeDecodeError或IOError,finally都要调用f.close() - 陷阱:在
finally里又抛出新异常,会吞掉原始异常;如需记录,用logging.exception()而非raise - 替代方案:优先用
with语句(自动触发__exit__),比手写finally更可靠
用 sys.exc_info() 在 except 或 finally 中获取当前异常信息
当需要在 finally 或通用清理函数里判断具体异常类型时,不能直接访问异常对象,得靠 sys.exc_info()。它返回 (type, value, traceback) 三元组,其中 type 就是异常类。
- 示例:在
finally里写exc_type, exc_val, _ = sys.exc_info(),再用isinstance(exc_type, ConnectionError)分支处理 - 注意:
sys.exc_info()在except块外可能返回(None, None, None),务必先判空 - 性能影响:调用本身开销小,但提取完整 traceback(第三个值)较重,日常日志只需
str(exc_val)即可
清理逻辑耦合到上下文管理器中更安全
把清理规则封装进自定义上下文管理器(实现 __enter__/__exit__),能让异常类型判断和清理动作天然绑定,避免散落在多处 except 块里。
- 比如数据库连接类的
__exit__(self, exc_type, exc_val, exc_tb)可以根据exc_type决定 rollback 还是 commit - 优势:调用方只需
with MyResource() as r:,不用重复写一堆except,逻辑集中、易测试 - 容易忽略的点:
__exit__返回True会抑制异常传播,除非你明确想吞掉错误,否则别随便 return True
真正难的不是写多个 except,而是理清哪些清理动作依赖异常类型、哪些必须无条件执行、哪些该交给上下文管理器——边界模糊时,程序会在看似正常的情况下悄悄漏掉关键清理步骤。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











