这个代码...

class Person:
    num_of_people = 0

    def __init__(self, name):
        self.name = name
        Person.num_of_people += 1

    def __del__(self):
        Person.num_of_people -= 1

    def __str__(self):
        return 'Hello, my name is ' + self.name

cb = Person('Corey')
kb = Person('Katie')
v = Person('Val')

产生以下错误...

Exception AttributeError: "'NoneType' object has no attribute 'num_of_people'" in <bound method Person.__del__ of <__main__.Person object at 0x7f5593632590>> ignored

但这个代码没有.

class Person:
    num_of_people = 0

    def __init__(self, name):
        self.name = name
        Person.num_of_people += 1

    def __del__(self):
        Person.num_of_people -= 1

    def __str__(self):
        return 'Hello, my name is ' + self.name

cb = Person('Corey')
kb = Person('Katie')
vb = Person('Val')

我看到的唯一区别是最后一个变量名是"vb"和"v".

我正在学习Python,现在正在研究OOP.

推荐答案

是的,虽然不是因为变量名的原因,也不是直接的原因.

当Python退出时,所有模块也会被删除.清理模块的方法是将模块中的所有全局变量设置为None(这样这些引用就不再引用原始对象).这些全局变量是dictionary对象中的键,由于字典的顺序是任意的,重命名一个变量可以改变变量的清除顺序.

当您将v重命名为vb时,您改变了清除变量的顺序,现在最后清除Person.

解决方法之一是在__del__方法中使用type(self).num_of_people -= 1:

def __del__(self):
    type(self).num_of_people -= 1

因为实例将始终具有对类的引用,如果Person未设置为None,则为test:

def __del__(self):
    if Person is not None:
        Person.num_of_people -= 1

两个注意事项:

  • CPython 3.4不再将globals设置为None(在大多数情况下),按照Safe Object Finalization;见PEP 442.

  • CPython 3.3自动对globals字典中使用的str个键应用randomized hash salt;这使得您观察到的行为更加随机,仅仅重新运行代码几次可能会或可能不会触发错误消息.

Python-3.x相关问答推荐

我有个问题继承遗产合伙人

如何使用Python将嵌套的XML转换为CSV

如何从枚举中获取某个值?

切片时是否在NumPy ND数组中创建新对象?

删除浮点型数据集中每列重复值比例超过一定阈值的列

基于组/ID从原始数据框中创建两个子数据框

如何将日期时间索引写入日期类型的表?

删除列表中的第二个出现

三重奏:为什么频道被记录为使用async with,而不是with?

列出相同索引的Pandas

Python多进程:运行一个类的多个实例,将所有子进程保留在内存中

spinbutton调整up/down箭头

python用户输入5个偶数并打印最大的

Python3 AttributeError:列表对象没有属性清除

具有 2 个输入的 python 3 map/lambda 方法

为什么中断比引发异常更快?

当 None 被传递时,如何将默认值应用于 python 数据类字段?

Python3 - 如何从现有抽象类定义抽象子类?

map 对象不是 JSON 可序列化的

finally 总是在 try 块返回之前运行,那么为什么 finally 块中的更新不会影响 try 块返回的变量的值呢?