Python 3 中编写自定义 __del__
方法或依赖 stdlib1 方法的用例有哪些?也就是说,在什么情况下它是相当安全的,并且可以做一些没有它很难做的事情?
出于许多充分的理由 ( 1 2 3 4 5 6 ),通常的建议是避免 __del__
而是使用上下文管理器或手动执行清理:
__del__
如果对象在解释器导出 2 上还活着,则不能保证被调用。- 在预期对象可以被销毁的那一刻,引用计数实际上可能是非零的(例如,引用可能通过调用函数持有的回溯帧而存活)。这使得销毁时间远比
gc
所暗示的不可预测性要不确定得多。 - 如果循环包含超过 1 个带有
__del__
的对象,则垃圾收集器无法摆脱循环 __del__
中的代码必须写得 super 仔细:__init__
中设置的对象属性可能不存在,因为__init__
可能引发异常;- 异常被忽略(只打印到
stderr
); - globals 可能不再可用。
更新:
PEP 442 对 __del__
的行为进行了重大改进。看来我的第 1-4 点仍然有效?
更新 2:
后 PEP 442 python(即 python 3.4+)中的一些顶级 python 库 embrace the use of __del__
。我想我的第 3 点在 PEP 442 之后不再有效,其他点被认为是对象终结不可避免的复杂性。
1我将问题从仅编写自定义 __del__
方法扩展为包括依赖 stdlib 中的 __del__
。
2似乎 __del__
在较新版本的 Cpython 中总是在解释器退出时被调用(有人有反例吗?)。然而,为了 __del__
的可用性目的并不重要:文档明确 provide no guarantee about this behavior ,所以不能依赖它(它可能在未来的版本中改变,并且在非CPython 解释器)。
最佳答案
上下文管理器(和 try
/finally
block )在某种程度上比 __del__
更具限制性。通常,它们要求您以这样一种方式构建代码,即您需要释放的资源的生命周期不会超出调用堆栈中某个级别的单个函数调用,而不是将其绑定(bind)到生命周期可能在不可预知的时间和地点被销毁的类实例。将资源的生命周期限制在一个范围内通常是一件好事,但有时在某些极端情况下,这种模式不适合使用。
我使用 __del__
的唯一情况(除了调试,c.f. @MSeifert 的回答)是为了释放由外部库在 Python 外部分配的内存。由于我包装的库的设计,很难避免有大量对象保存指向堆分配内存的指针。使用 __del__
方法释放指针是最简单的清理方法,因为将每个实例的生命周期包含在上下文管理器中是不切实际的。
关于python - __del__ 的用例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43666794/