gpt4 book ai didi

python - 为什么新样式类和旧样式类在这种情况下有不同的行为?

转载 作者:太空狗 更新时间:2023-10-29 18:04:32 25 4
gpt4 key购买 nike

我发现了一些有趣的东西,这是一段代码:

class A(object):
def __init__(self):
print "A init"

def __del__(self):
print "A del"

class B(object):
a = A()

如果我运行这段代码,我会得到:

A init

但是如果我将 class B(object) 更改为 class B(),我将得到:

A init
A del

我在 __del__ doc 中找到了一条注释:

It is not guaranteed that del() methods are called for objects that still exist when the interpreter exits.

然后,我猜这是因为当解释器存在时,B.a 仍然被引用(被类 B 引用)。

所以,我在解释器存在前手动添加了一个del B,然后发现调用了a.__del__()

现在,我对此有点困惑。为什么在使用旧样式类时调用 a.__del__()?为什么新旧样式类有不同的行为?

我发现了一个类似的问题here ,但我认为答案还不够明确。

最佳答案

TL;DR:这是一个 old issue在 CPython 中,这最终在 CPython 3.4 中得到修复.在 3.4 之前的 CPython 版本中,由模块全局引用的引用循环保持事件的对象在解释器退出时未正确完成。新型类在它们的 type 实例中有隐式循环;旧式类(classobj 类型)没有隐式引用循环。

即使在这种情况下已修复,CPy​​thon 3.4 文档仍然建议不要依赖 __del__在口译员退出时被要求 - 认为自己受到警告。


新样式类本身具有引用循环:最值得注意的是

>>> class A(object):
... pass
>>> A.__mro__[0] is A
True

这意味着它们不能立即删除*,只能在垃圾收集器运行时删除。由于对它们的引用由主模块持有,因此它们将保留在内存中,直到解释器关闭。最后,在模块清理期间,main 中的所有模块全局名称都设置为指向 None,并且无论哪个对象的引用计数都减少到零(您的旧式类例如)也被删除。但是,具有引用循环的新型类不会因此发布/最终确定。

循环垃圾收集器不会在解释器导出运行(CPython documentation 允许:

It is not guaranteed that __del__() methods are called for objects that still exist when the interpreter exits.


现在,Python 2 中的旧式类没有隐式循环。当 CPython 模块清理/关闭代码将全局变量设置为 None 时,唯一剩余的对类 B 的引用将被删除;然后 B 被删除,最后一个对 a 的引用被删除,a 也被最终确定。


为了证明新式类有循环并需要 GC 清除,而旧式类没有,您可以在 CPython 2 中尝试以下程序(CPython 3 没有任何旧式类更多):

import gc
class A(object):
def __init__(self):
print("A init")

def __del__(self):
print("A del")

class B(object):
a = A()

del B
print("About to execute gc.collect()")
gc.collect()

如上以B为new-style class,输出为

A init
About to execute gc.collect()
A del

B作为旧式类(class B:),输出为

A init
A del
About to execute gc.collect()

也就是说,新样式类仅在 gc.collect() 之后被删除,即使对它的最后一个外部引用已经被删除;但旧式类立即被删除。


其中大部分已经是 fixedPython 3.4 :感谢PEP 442 ,其中包括 module shutdown procedure based on GC code .现在,即使在解释器退出时,模块全局变量也会使用普通垃圾收集完成。如果您在 Python 3.4 下运行您的程序,程序将打印

A init
A del

而使用 Python <=3.3 它将打印

A init

(请注意此时其他实现仍然可能会或可能不会执行 __del__,无论它们的版本是高于、等于还是低于, 3.4)

关于python - 为什么新样式类和旧样式类在这种情况下有不同的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29511332/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com