真正的异常安全是确保程序在任何路径下都不泄露资源、不破坏状态;应优先用with管理资源,谨慎处理__exit__中的异常,清理逻辑放finally,避免在__init__中分配关键资源。

写Python代码时,异常处理不只是“用try-except包起来”,关键在于:资源是否被正确释放、状态是否保持一致、错误是否被合理传递。真正的异常安全,是让程序在任何路径(包括抛出异常)下,都不泄露文件句柄、不卡死锁、不留下临时文件、不破坏对象不变量。
用with语句自动管理资源
手动调用close()、unlock()、cleanup()极易遗漏——尤其在异常中途跳出时。with语句通过上下文管理器(__enter__/__exit__)确保退出逻辑一定执行,是最简单可靠的资源清理方式。
- 文件操作优先用with open(...),不用f = open(); ...; f.close()
- 线程锁用with lock:,避免忘记release导致死锁
- 数据库连接、临时目录、网络套接字等,只要支持上下文协议,都应走with流程
__exit__中谨慎处理异常
自定义上下文管理器的__exit__(exc_type, exc_val, exc_tb)方法会在退出时被调用。它返回True可抑制异常(不往外抛),返回None或False则继续传播。多数情况下,你不该吞掉异常。
- 清理逻辑(如删除临时文件)应放在__exit__开头,与异常类型无关
- 若清理过程自身可能出错,应单独捕获并记录,避免掩盖原始异常
- 不要在__exit__里raise新异常,除非你明确要替换原异常(需谨慎)
finally比except更可靠
当必须执行某段清理代码,且不关心是否发生异常、也不需要捕获异常本身时,finally比except更直接、更安全。
立即学习“Python免费学习笔记(深入)”;
- 比如手动打开的socket,即使parse_data()抛ValueError,也要close()
- 避免在except里重复写清理逻辑;多个except分支共用同一段清理?直接提进finally
- 注意:finally中的return或raise会覆盖try/except里的返回值或异常,慎用
避免在构造函数中分配关键资源
如果__init__里打开文件、建连接、加锁,而初始化中途失败,对象可能处于半构建状态,无法靠__del__可靠清理(__del__不保证何时调用,甚至可能不调用)。
- 改用工厂函数或显式init()方法分离资源获取和对象创建
- 或让__init__只做轻量赋值,资源延迟到首次使用时获取(配合属性装饰器+缓存)
- 若必须在__init__中申请,确保有配套的__del__ + 显式close()双保险,并文档注明“必须调用close”










