我正在读代码。有一个类定义了__del__
方法。我发现这个方法用于销毁类的实例。但是,我找不到使用此方法的地方。主要原因是我不知道如何使用这种方法,可能不是这样:obj1.del()
。那么,我的问题是如何调用__del__
方法?谢谢你的帮助。
答案 0 :(得分:118)
__del__
是终结者。当一个对象垃圾收集时调用它,该对象在删除了对该对象的所有引用之后的某个时刻发生。
在简单的情况中,这可能是在您说del x
之后,或者如果x
是局部变量,则在函数结束后。特别是,除非有循环引用,否则CPython(标准Python实现)将立即进行垃圾收集。
但是,这是CPython的实现细节。 Python垃圾收集的唯一必需属性是在所有引用都被删除后发生,因此可能不必在之后发生和<强>可能根本不会发生。
更重要的是,变量可以长时间存在<很多原因,例如传播异常或模块内省可以使变量引用计数大于0.此外,变量可以是引用循环的一部分 - 启用垃圾收集的CPython会破坏大多数但不是全部,这样的循环,甚至只是定期。
由于您无法保证它已被执行,因此永远不会将您需要运行的代码放入__del__()
- 相反,此代码属于finally
条款try
块或with
语句中的上下文管理器。但是,__del__
有有效用例:例如:如果对象X
引用了Y
并且还在全局Y
(cache
)中保留了cache['X -> Y'] = Y
引用的副本,那么{{1}将是礼貌的还要删除缓存条目。
如果您知道析构函数提供(违反上述指南)必要的清理工作,您可能需要直接调用,因为没有什么特别之处它作为一种方法:X.__del__
。显然,只有当你知道它不介意被召唤两次时你才应该这样做。或者,作为最后的手段,您可以使用
x.__del__()
答案 1 :(得分:54)
我写了另一个问题的答案,尽管这是一个更准确的问题。
How do constructors and destructors work?
这是一个有点自以为是的答案。
请勿使用__del__
。这不是C ++或为析构函数构建的语言。 {3.}}方法确实应该在Python 3.x中消失,但我确信有人会找到一个有意义的用例。如果您需要使用__del__
,请注意每个http://docs.python.org/reference/datamodel.html的基本限制:
__del__
被调用,而不是在您丢失对象的最后一个引用时,而不是在您执行__del__
时。del object
负责调用超类中的任何__del__
,但不清楚这是在方法解析顺序(MRO)中还是仅调用每个超类。__del__
意味着垃圾收集器放弃检测和清除任何循环链接,例如丢失对链表的最后一个引用。您可以从gc.garbage获取忽略的对象列表。有时您可以使用弱引用来完全避免循环。这有时会引起争议:见http://mail.python.org/pipermail/python-ideas/2009-October/006194.html。__del__
函数可以作弊,保存对象的引用,并停止垃圾回收。__del__
中明确提出的例外情况。__del__
补充__del__
远远超过__new__
。这让人感到困惑。有关解释和问题,请参阅http://www.algorithm.co.il/blogs/programming/python-gotchas-1-del-is-not-the-opposite-of-init/。__init__
不是Python中“深受喜爱”的孩子。您会注意到sys.exit()文档没有指定在退出之前是否收集垃圾,并且存在许多奇怪的问题。在全局变量上调用__del__
会导致奇怪的排序问题,例如http://bugs.python.org/issue5099。即使__del__
失败,__del__
是否应该调用?有关长线程,请参阅http://mail.python.org/pipermail/python-dev/2000-March/thread.html#2423。但是,另一方面:
__init__
表示你不要忘记致电一个密切的陈述。有关专家__del__
观点,请参阅http://eli.thegreenplace.net/2009/06/12/safely-using-destructors-in-python/。这通常是关于释放ctypes或其他一些特殊资源。我个人不喜欢__del__
功能的原因。
__del__
时,它就会变成三十条混乱信息。因此,找个理由不使用__del__
。
答案 2 :(得分:11)
__del__
方法,当对象被垃圾收集时将调用它。请注意,它不一定能保证被调用。以下代码本身不一定会这样做:
del obj
原因是del
只是将引用计数减1。如果其他内容引用了该对象,则__del__
将不会被调用。
但使用__del__
时有一些注意事项。通常,它们通常不是很有用。听起来我更像是想要使用close方法或with statement。
请参阅python documentation on __del__
methods。
另外需要注意的一点是:__del__
方法可以在过度使用时禁止垃圾回收。特别是,具有多个具有__del__
方法的对象的循环引用不会被垃圾收集。这是因为垃圾收集器不知道首先调用哪一个。有关详细信息,请参阅gc module上的文档。
答案 3 :(得分:8)
当您的对象最终被销毁时,将调用__del__
方法(注释拼写!)。从技术上讲(在cPython中)就是没有更多对你的对象的引用,即当它超出范围时。
如果要删除对象,请调用__del__
方法
del obj1
将删除该对象(前提是没有任何其他引用)。
我建议你写一个这样的小班
class T:
def __del__(self):
print "deleted"
在python解释器中进行调查,例如
>>> a = T()
>>> del a
deleted
>>> a = T()
>>> b = a
>>> del b
>>> del a
deleted
>>> def fn():
... a = T()
... print "exiting fn"
...
>>> fn()
exiting fn
deleted
>>>
请注意,jython和ironpython对于删除对象和调用__del__
的确切时间有不同的规则。尽管如此,使用__del__
并不是一种好的做法,因为在调用它时,对象及其环境可能处于未知状态。绝对不会保证调用__del__
- 解释器可以以各种方式退出而不删除所有对象。
答案 4 :(得分:0)
如前所述,__del__
功能有些不可靠。在看起来有用的情况下,请考虑使用__enter__
和__exit__
方法。这将产生类似于用于访问文件的with open() as f: pass
语法的行为。进入__enter__
的范围时,会自动调用with
,而退出时会自动调用__exit__
。有关更多详细信息,请参见this question。