我想了解对象删除在 python 上的工作原理。这是一组非常简单的代码。
class A(object):
def __init__(self):
setattr(self, "test", self._test)
def _test(self):
print "Hello, World!"
def __del__(self):
print "I'm dying!"
class B(object):
def test(self):
print "Hello, World!"
def __del__(self):
print "I'm dying"
print "----------Test on A"
A().test()
print "----------Test on B"
B().test()
Pythonista 会识别出我运行的是 python 2.x 版本。更具体地说,此代码在 python 2.7.1 设置上运行。
此代码输出以下内容:
----------Test on A
Hello, World!
----------Test on B
Hello, World!
I'm dying
令人惊讶的是,A
对象没有被删除。我能理解为什么,因为 __init__
中的 setattr
语句产生了循环引用。但这一个似乎很容易解决。
最后,这个页面,在python documentation (Supporting Cyclic Garbage Collection) , 表明可以处理这种循环引用。
我想知道:
- 为什么我从不在
A
类中使用我的__del__
方法? - 如果我对循环引用的诊断是好的,为什么我的
object
子类不支持循环垃圾回收? - 最后,如果我真的想通过
__del__
,如何处理这种setattr
?
注意:在A
中,如果setattr
指向我模块的另一个方法,没有问题。
最佳答案
事实 1
实例方法通常存储在类 中。解释器首先在失败的实例 __dict__
中查找它们,然后在成功的类中查找。
当您在__init__
中动态设置A
的实例方法时,您会在实例字典中创建对它的引用。此引用是循环的,因此引用计数永远不会变为零,引用计数器也不会清除 A
。
>>> class A(object):
... def _test(self): pass
... def __init__(self):
... self.test = self._test
...
>>> a = A()
>>> a.__dict__['test'].im_self
事实 2
垃圾收集器是 Python 用来处理循环引用的工具。不幸的是,它无法处理具有 __del__
方法的对象,因为通常它无法确定调用它们的安全顺序。相反,它只是将所有此类对象放入 gc.garbage
中。然后你可以去那里看看打破循环,这样他们就可以被释放。来自docs
gc.garbage
A list of objects which the collector found to be unreachable but could not be freed (uncollectable objects). By default, this list contains only objects with
__del__()
methods. Objects that have__del__()
methods and are part of a reference cycle cause the entire reference cycle to be uncollectable, including objects not necessarily in the cycle but reachable only from it. Python doesn’t collect such cycles automatically because, in general, it isn’t possible for Python to guess a safe order in which to run the__del__()
methods. If you know a safe order, you can force the issue by examining the garbage list, and explicitly breaking cycles due to your objects within the list. Note that these objects are kept alive even so by virtue of being in the garbage list, so they should be removed from garbage too. For example, after breaking cycles, dodel gc.garbage[:]
to empty the list. It’s generally better to avoid the issue by not creating cycles containing objects with__del__()
methods, andgarbage
can be examined in that case to verify that no such cycles are being created.
因此
如果您希望对象被垃圾回收,请不要使用 __del__
方法对对象进行循环引用。
关于python - setattr、对象删除和循环垃圾回收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9827392/