当试图理解一些Python概念时,我遇到了以下问题:
class A:
def __init__(self, x):
self.x = x
def __del__(self):
print("del")
a1 = A()
输出:
$ python test.py
del
Traceback (most recent call last):
File "testdest.py", line 9, in <module>
a1 = A()
TypeError: __init__() takes exactly 2 arguments (1 given)
错误是显而易见的(实例化时缺少参数),但我想知道为什么在拥有实例之前调用析构函数?
除非在尝试实例化时,Python甚至在调用构造函数之前创建了一种实例,并且需要在结束时进行清理?
由于self
被传递给构造函数,我可以假设这个self
是实例吗?这是真的,那么在调用构造函数时实例已经存在,是吗?
这是垃圾收集器的行为,可能取决于当前的实现吗?
答案 0 :(得分:5)
来自Python文档:
永远不会明确销毁对象;然而,当他们成为 无法到达,他们可能被垃圾收集。一个实现是 允许推迟垃圾收集或完全省略 - 这是一个 垃圾收集的实施质量问题 实现,只要没有收集任何仍然存在的对象 可到达的。
object.__init__(self[, ...])
在创建实例后调用(通过 new ()), 但在它返回给调用者之前。 [...]
object.__del__(self)
当实例即将被销毁时调用。 [...]
因此,当__init__
被调用时,对象实例已经存在,因为它是由__new__
创建的。但对于Python,一般来说,无法保证__del__
将被调用。
以下仅适用于CPython,即Python的参考实现。
注意(适用于
object.__del__(self)
)del x不直接
call x.__del__()
- 前者递减了 x的引用计数为1,后者仅在x时被调用 引用计数达到零。 [...]
只要实例的引用计数降为0,就会调用__del__
。这与垃圾收集无关。一个小实验:
>>> class A:
... def __del__(self): print "del"
...
>>> a = A()
>>> a = None
del
>>> import gc
>>> gc.disable()
>>> a = A()
>>> a = None
del
如您所见,即使明确禁用了GC,也会调用析构函数。
请注意,这也意味着如果对象层次结构中有循环,则最终会得到永远不会调用__del__
的对象,因为Python GC无法处理引用循环。
>>> a1 = A()
>>> a2 = A()
>>> a1.x = a2
>>> a2.x = a1
>>> a1 = None
>>> a2 = None
>>> import gc
>>> gc.collect()
4
>>> gc.garbage
[<__main__.A instance at 0x7f2c66a1d7e8>, <__main__.A instance at 0x7f2c66a1d830>]