为啥 Python 在对象之前销毁类变量?

Posted

技术标签:

【中文标题】为啥 Python 在对象之前销毁类变量?【英文标题】:Why does Python destroy class variables before objects?为什么 Python 在对象之前销毁类变量? 【发布时间】:2013-03-02 07:37:24 【问题描述】:

我了解 Python 不保证程序结束时对象的销毁顺序,甚至不保证会发生。

所以我明白一个类的析构函数不能依赖全局变量,包括其他模块。

但我会认为类的对象必须在类被销毁之前被销毁。显然不是:

class A(object):
    count = 0
    def __init__(self):
        A.count += 1
        print 'Creating object, there are now', A.count
    def __del__(self):
        A.count -= 1
        print 'Destroying object, there are now', A.count

a1 = A()
a2 = A()

在 Windows 7 x64 Python v2.7.3 上,我得到:

Creating object, there are now 1
Creating object, there are now 2
Exception AttributeError: "'NoneType' object has no attribute 'count'" in <bound
 method A.__del__ of <__main__.A object at 0x0234B8B0>> ignored
Exception AttributeError: "'NoneType' object has no attribute 'count'" in <bound
 method A.__del__ of <__main__.A object at 0x0234BE90>> ignored

我了解How do I correctly clean up a Python object? 的含义。但这种情况适用于类(我的 C++ 朋友的共享或“静态”)变量。实例肯定有对类变量的引用,不应该先销毁它,因为我们还有对它的引用?

在该类的对象之前销毁该类是问题还是错误? 也许我的问题是“类共享变量实际存储在哪里?”

(是的,我知道这可以使用上下文管理器来纠正,甚至可以简单地纠正:

del a1
del a2

在类被销毁之前销毁对象。)

【问题讨论】:

【参考方案1】:

也许我的问题是“类共享变量实际存储在哪里?”

如果这是你的问题,答案是“在课堂上”。

解决您更大的问题:正如您所指出的,__del__ 不能依赖全局变量 - 但 A 是全局变量,因此您不能依赖它。有趣的是,我在文档中找不到对此的官方声明,但互联网上有各种参考资料表明__del__ 不能使用全局变量。 Here是一:

当 Python 程序终止时,每个模块中的全局变量都设置为 None。发生这种情况的顺序未定义

如果您通过self.__class__.count 而不是A.count 访问计数,它将起作用。 (这也是你使用self.count时它起作用的原因。)

【讨论】:

实例上的.__class__ 怎么样? @FatalError:你是对的,参考问题是一个红鲱鱼。问题不在于类本身已被删除,而是引用它的全局变量已设置为无。我编辑了我的答案。 奇怪的是,当我尝试使用 .__class__ 时,我得到了相同的行为。在这种情况下,它似乎在调用__del__ 之前也设置为None,这有点令人惊讶。 @FatalError:您是否将-=print 都更改为使用self.__class__?我以为我也看到了你所看到的,但我还在做print A.count 通过环境设置PYTHONVERBOSE=2可以看到模块清理和属性清理的顺序。

以上是关于为啥 Python 在对象之前销毁类变量?的主要内容,如果未能解决你的问题,请参考以下文章

java中静态成员变量、实例变量、局部变量何时创建、何时销毁?

变量按作用域划分

Java——变量

JAVA类与对象---实例变量与类变量的区别,实例方法和类方法的区别

为啥使用类变量的这段代码不能像在 Java 中那样工作? [复制]

为啥从类中访问类变量需要“自我”。在 Python 中? [复制]