Python setattr、对象删除和循环垃圾回收
我想了解对象删除在python上是如何工作的。下面是一组非常简单的代码Python setattr、对象删除和循环垃圾回收,python,garbage-collection,setattr,Python,Garbage Collection,Setattr,我想了解对象删除在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
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会意识到我正在运行Python2.x版本。更特别的是,这段代码在Python2.7.1设置上运行
此代码输出以下内容:
----------Test on A
Hello, World!
----------Test on B
Hello, World!
I'm dying
令人惊讶的是,对象没有被删除。我可以理解为什么,因为\uuuu init\uuuu
中的setattr
语句生成循环引用。但这个问题似乎很容易解决
最后,在中的这一页显示,处理这种循环引用是可能的
我想知道:
- 为什么我从来没有在
A
类中使用我的\uu del\uu
方法
- 如果我对循环引用的诊断是正确的,为什么我的
对象
子类不支持循环垃圾收集
- 最后,如果我真的想通过
\uuu del\uuu
,如何处理这种setattr
注意:在A
中,如果setattr
指向我模块的另一个方法,则没有问题。您应该非常仔细地阅读该方法-特别是,带有\u del\u
方法的对象改变收集器工作方式的部分
提供了一些钩子,您可以自己清理
我怀疑这里没有\uuu del\uu
方法会导致对象被正确清理。您可以通过查看gc.garbage
并查看A
的实例是否存在来验证这一点。Fact 1
实例方法通常存储在类中。解释器首先在实例\uuuu dict\uuuu
中查找它们,该实例失败,然后查看类,该类成功
当您在\uuu init\uuu
中动态设置A
的实例方法时,您将在实例字典中创建对它的引用。此引用是循环的,因此refcount永远不会变为零,引用计数器也不会清除A
up
>>> class A(object):
... def _test(self): pass
... def __init__(self):
... self.test = self._test
...
>>> a = A()
>>> a.__dict__['test'].im_self
事实2
垃圾收集器是Python用来处理循环引用的。不幸的是,它不能用方法处理对象,因为通常它不能确定调用它们的安全顺序。相反,它只是将所有此类对象放入gc.garbage
。然后你可以到那里去打破循环,这样它们就可以被释放。从
收集器发现无法访问但无法访问的对象的列表
无法释放(无法收集的对象)。默认情况下,此列表仅包含
具有\uuu del\uuu()方法的对象。具有方法的对象
是参考循环的一部分,导致整个参考循环
无法收回,包括不一定要收回的物品
在循环中,但只能从循环中访问。Python不收集这样的数据
自动循环,因为在一般情况下,Python不可能这样做
猜测运行方法的安全顺序。如果你
如果你知道一个安全的命令,你可以通过检查垃圾来强制解决这个问题
列表中的对象,并显式中断循环
列表请注意,即使如此,由于
在垃圾列表中,所以它们也应该从垃圾中移除。
例如,在中断循环后,执行del gc.garbage[:]
清空
列表通常最好不要创建循环来避免问题
可以检查包含具有\uu del\uu()方法和垃圾的对象
在这种情况下,验证是否未创建此类循环
所以
如果希望对象被垃圾收集,请不要对具有方法的对象进行循环引用。我怀疑setattr
与此有关。您正在存储一个绑定方法,该方法存储对象。您还可以通过常规分配来存储它(self.test=self.\u test
)。请尝试一下,如果它产生相同的输出,你可以简化这个问题。哦,是的,它产生相同的东西。但是,self.test=self.\u test
调用对象的\u setattr\u
属性。我说得对吗?是的,但是设置属性也应该这样做。我相信setattr
甚至尊重属性。。。。启用选项cycle detector时(默认情况下,它处于启用状态)会检测到垃圾循环引用,但只有在没有涉及Python级别的\uu del\uu()
方法的情况下才能清除垃圾循环引用。那么,在python级别使用del方法会破坏循环检测器吗?ohe:我的答案指向gc模块垃圾变量,您可以对该变量进行操作以打破循环。这非常烦人。事实上,我总是知道如何打破循环。但我想在对象删除时这样做,这就是为什么我们“重写”\uuu del\uuu
语句(否则,我为什么要写这个语句;)。事实上,我可以通过调用del gc.garbage[:]
查看这个gc.garbage
列表,打破循环,删除对象,但是,正如我所说,我发现了这个。。。。烦人的谢谢你的聪明和快速的回答。@ohe我显然不知道你的案例的具体情况,但我认为更自然的解决办法是定义某种.finish()
方法——你完成后调用它——它打破了循环。
gc.garbage