__del__常不被调用,因其依赖引用计数归零且无循环引用,而循环引用需gc介入且时机不确定;禁止在其中执行文件关闭、网络请求、日志记录等关键操作。

不建议依赖 __del__ 做关键资源清理,它不可靠、不可预测,且可能引发引用循环或异常静默。
为什么 __del__ 经常不被调用?
Python 的垃圾回收主要靠引用计数,但循环引用必须等周期性 GC(如 gc.collect())介入。一旦对象陷入循环引用,__del__ 就不会在对象“该销毁时”执行——甚至永远不会执行。
- 常见于类中持有自身实例的回调、闭包、观察者列表等场景
- 若
__del__抛出异常,Python 会静默忽略,你根本收不到报错 - 程序退出时,模块全局变量的销毁顺序不确定,
__del__中访问其他模块对象可能已为None
哪些操作绝对不能放在 __del__ 里?
任何需要强保证、强顺序、强可用性的逻辑都不适合。
- 关闭文件或网络连接:用
with或显式.close()替代 - 释放锁(
threading.Lock):可能死锁,且锁对象本身可能已被回收 - 写日志、发 HTTP 请求、调用数据库:模块已卸载或事件循环已关闭,大概率失败
- 修改全局状态(如从注册表中移除自己):GC 时机不可控,容易漏删或重复删
如果非要写 __del__,怎么降低风险?
仅限调试、统计、极简标记类用途;务必防御性编码。
- 避免访问外部模块名或全局变量,改用
sys.modules检查是否存在 - 所有操作包在
try/except中,且不要裸except,至少捕获AttributeError和RuntimeError - 不要在
__del__中再创建新对象(如字符串格式化可能触发内存分配) - 示例:
def __del__(self): try: if hasattr(self, '_fd') and self._fd and not self._fd.closed: self._fd.close() except (AttributeError, ValueError, OSError): pass
真正要确保执行的销毁逻辑,始终优先走上下文管理器(__enter__/__exit__)、显式 close() 方法,或使用 weakref.finalize()——它比 __del__ 更可预测,且能明确绑定到对象生命周期终点。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











