__del__的用例 [英] Use cases for __del__
问题描述
在python 3中编写自定义 __ del __
方法或依赖stdlib 1 中的一个的用例是什么?也就是说,在什么情况下它是相当安全的,如果没有它,它可以做一些很难做的事情?
What are use cases in python 3 of writing a custom __del__
method or relying on one from stdlib1? That is, in what scenario is it reasonably safe, and can do something that's hard to do without it?
出于许多充分的原因(1 2 3 4 5 6 ),通常的建议是避免使用 __ del __
,而是使用上下文管理器或手动执行清除操作:
For many good reasons (1 2 3 4 5 6), the usual recommendation is to avoid __del__
and instead use context managers or perform the cleanup manually:
-
__ del __
在解释器出口 2 上还活着。 - 在这一点上,人们期望对象可以被销毁,引用计数实际上可能为非零(例如,引用可能在调用函数保留的Raceback框架)。这使得销毁时间远比
gc
所暗示的仅不可预测性更不确定。 - 如果垃圾收集器包含以下内容,则它们无法摆脱循环
__ del __
的多个对象 -
__ del __
内的代码必须编写超级小心:
- 在
__ init __
中设置的对象属性可能不存在,因为__init __
可能引发了异常; - 异常被忽略(仅打印到
stderr
); - 全局变量可能不再可用。
- 在
__del__
is not guaranteed to be called if objects are alive on intrepreter exit2.- At the point one expects the object can be destroyed, the ref count may actually be non-zero (e.g., a reference may survive through a traceback frame held onto by a calling function). This makes the destruction time far more uncertain than the mere unpredictability of
gc
implies. - Garbage collector cannot get rid of cycles if they include more than 1 object with
__del__
- The code inside
__del__
must be written super carefully:- object attributes set in
__init__
may not be present since__init__
might have raised an exception; - exceptions are ignored (only printed to
stderr
); - globals may no longer be available.
- object attributes set in
更新:
Update:
PEP 442 对 __ del __
的行为进行了重大改进。看来我的第1-4点仍然有效?
PEP 442 has made significant improvements in the behavior of __del__
. It seems though that my points 1-4 are still valid?
更新2:
一些顶级python库拥抱<$ c $的使用在PEP 442后的python中(即python 3.4+)中的c> __ del __ 。我想我的观点3在PEP 442之后不再有效,而其他观点则被认为是不可避免的对象完成复杂性。
Some of the top python libraries embrace the use of __del__
in the post-PEP 442 python (i.e., python 3.4+). I guess my point 3 is no longer valid after PEP 442, and the other points are accepted as unavoidable complexity of object finalization.
1 我将问题从仅仅编写自定义 __ del__扩展了
方法包括依赖于stdlib中的 __ del __
。
1I expanded the question from just writing a custom __del__
method to include relying on __del__
from stdlib.
2 在最新版本的Cpython中,似乎总是在解释器出口上调用 __ del __
(有人反对吗?)。但是,对于 __ del __
的实用性而言,这并不重要:文档显式地不提供有关此行为的保证,因此不能依赖它(它可能在将来的版本中更改,并且在非CPython解释器中可能有所不同) )。
2It seems that __del__
is always called on interpreter exit in the more recent versions of Cpython (does anyone have a counter-example?). However, it doesn't matter for the purpose of __del__
's usablity: the docs explicitly provide no guarantee about this behavior, so one cannot rely on it (it may change in future versions, and it may be different in non-CPython interpreters).
推荐答案
上下文管理器(和 try
/ 最终
块)比 __ del __
更具限制性。通常,它们要求您以某种方式来构造代码,以使您需要释放的资源的生存期不会超出调用堆栈中某个级别的单个函数调用,而不是将其绑定到生存期类实例的实例,该实例可能在不可预测的时间和地点被破坏。将资源的生命周期限制在一个范围内通常是一件好事,但是有时在某些极端情况下,这种模式很不合适。
Context managers (and try
/finally
blocks) are somewhat more restrictive than __del__
. In general they require you to structure your code in such a way that the lifetime of the resource you need to free doesn't extend beyond a single function call at some level in the call stack, rather than, say, binding it to the lifetime of a class instance that could be destroyed at unpredictable times and places. It's usually a good thing to restrict the lifetime of resources to one scope, but there sometimes edge cases where this pattern is an awkward fit.
__ del __
(用于调试,请参见@MSeifert的回答)是用于释放外部库在Python外部分配的内存。由于我要包装的库的设计,很难避免拥有大量持有指向堆分配内存的指针的对象。使用 __ del __
方法释放指针是清理的最简单方法,因为将每个实例的寿命包含在上下文管理器中是不切实际的。
The only case where I've used __del__
(aside from for debugging, c.f. @MSeifert's answer) is for freeing memory allocated outside of Python by an external library. Because of the design of the library I was wrapping, it was difficult to avoid having a large number of objects that held pointers to heap-allocated memory. Using a __del__
method to free the pointers was the easiest way to do cleanup, since it would have been impractical to enclose the lifespan of each instance inside a context manager.
这篇关于__del__的用例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!