__del__的用例 [英] Use cases for __del__

查看:117
本文介绍了__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:


  1. __ del __ 在解释器出口 2 上还活着。

  2. 在这一点上,人们期望对象可以被销毁,引用计数实际上可能为非零(例如,引用可能在调用函数保留的Raceback框架)。这使得销毁时间远比 gc 所暗示的仅不可预测性更不确定。

  3. 如果垃圾收集器包含以下内容,则它们无法摆脱循环 __ del __
  4. 的多个对象
  5. __ del __ 内的代码必须编写超级小心:


    • __ init __ 中设置的对象属性可能不存在,因为 __init __ 可能引发了异常;

    • 异常被忽略(仅打印到 stderr );
    • 全局变量可能不再可用。

  1. __del__ is not guaranteed to be called if objects are alive on intrepreter exit2.
  2. 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.
  3. Garbage collector cannot get rid of cycles if they include more than 1 object with __del__
  4. 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.






更新:


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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆