Подтвердить что ты не робот

Может ли простая разница в именах переменных Python3 изменять способ запуска кода?

Этот код...

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" vs. "v".

Я склоняюсь к Python и сейчас работаю над материалом OOP.

4b9b3361

Ответ 1

Да, хотя это не так много имя переменной, которое вызывает это, а не напрямую.

При выходе из Python все модули также удаляются. Очистка модулей производится путем установки всех глобальных переменных в модуле на None (поэтому эти ссылки больше не относятся к исходным объектам). Эти глобальные ключи являются ключами словарного объекта, и, поскольку словари упорядочены произвольно, переименование одной переменной может изменить порядок, в котором переменные очищаются.

Когда вы переименовали v в vb, вы изменили порядок, в котором сбрасываются переменные, и теперь Person очищается последним.

Один подход - использовать type(self).num_of_people -= 1 в методе __del__:

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

потому что экземпляр всегда будет ссылаться на класс по-прежнему или проверить, не установлен ли Person на None:

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

Две заметки:

  • CPython 3.4 больше не устанавливает глобальные значения в None (в большинстве случаев), согласно Безопасное завершение объекта; см. PEP 442.

  • CPython 3.3 автоматически применяет рандомизированную соль хеша клавишам str, используемым в словаре globals; это приводит к тому, что поведение, которое вы наблюдаете, еще более случайное, просто повторное выполнение кода несколько раз может или не может вызвать сообщение об ошибке.