Метод __del__ не срабатывает вместе с методом __new__ в python
Метод __del__
не срабатывает вместе с методом __new__
в python, а отдельно очень даже хорошо работает. Т.е. я закомментирую __new__
, __del__
работает, активирую - __new__
работает, __del__
нет.
class House:
houses_history = []
def __new__(cls, *args, **kwargs):
cls.houses_history.append(args[0])
def __init__(self, name, number_of_floors):
self.name = name
self.number_of_floors = number_of_floors
def __del__(self):
print(f'{self.name} снесён, но он останется в истории')
h1 = House('ЖК Эльбрус', 10)
print(House.houses_history)
h2 = House('ЖК Акация', 20)
print(House.houses_history)
h3 = House('ЖК Матрёшки', 20)
print(House.houses_history)
# Удаление объектов
del h2
del h3
print(House.houses_history)
Как это исправить?
Ответы (3 шт):
У вас объекты не создаются вообще (т.к. ваш переопределенный __new__
ничего не возвращает, а значит возвращает None
), поэтому и удаляться нечему. Чтобы убедиться, что не создаются, достаточно через print
вывести содержимое переменных h1
, h2
, h3
- там будет None
(то что ваш __new__
вернул, то и записалось в переменные).
Чтобы код работал, нужно вызывать исходный __new__
:
class House:
houses_history = []
def __new__(cls, *args, **kwargs):
cls.houses_history.append(args[0])
return super().__new__(cls) # <- добавлено
def __init__(self, name, number_of_floors):
self.name = name
self.number_of_floors = number_of_floors
def __del__(self):
print(f'{self.name} снесён, но он останется в истории')
h1 = House('ЖК Эльбрус', 10)
print(House.houses_history)
h2 = House('ЖК Акация', 20)
print(House.houses_history)
h3 = House('ЖК Матрёшки', 20)
print(House.houses_history)
# Удаление объектов
del h2
del h3
print(House.houses_history)
Вывод:
['ЖК Эльбрус']
['ЖК Эльбрус', 'ЖК Акация']
['ЖК Эльбрус', 'ЖК Акация', 'ЖК Матрёшки']
ЖК Акация снесён, но он останется в истории
ЖК Матрёшки снесён, но он останется в истории
['ЖК Эльбрус', 'ЖК Акация', 'ЖК Матрёшки']
ЖК Эльбрус снесён, но он останется в истории
В целом, оператор del
не удаляет принудительно объект, а только освобождает указанную переменную (и таким образом уменьшает счетчик ссылок объекта на 1). Если объект окажется сохранен где-то еще, то он не будет удален, и __del__
не сработает.
Все __del__
точно сработают только при завершении программы, когда удалятся вообще все объекты (поэтому мы и видим удаление "ЖК Эльбрус" в конце, хотя del
не вызывали).
А принципиально использовать __new__
? В принципе и через инициализатор можно добавить, результат вроде такой же или я ошибаюсь?
class House:
houses_history = []
# def __new__(cls, *args, **kwargs):
# cls.houses_history.append(args[0])
# return super().__new__(cls) # <- добавлено
def __init__(self, name, number_of_floors):
self.name = name
self.number_of_floors = number_of_floors
House.houses_history.append(name)
def __del__(self):
print(f'{self.name} снесён, но он останется в истории')
h1 = House('ЖК Эльбрус', 10)
print(House.houses_history)
h2 = House('ЖК Акация', 20)
print(House.houses_history)
h3 = House('ЖК Матрёшки', 20)
print(House.houses_history)
# Удаление объектов
del h2
del h3
print(House.houses_history)
тут ещё вариант решения предложили - использовать декоратор @classmethod
. Тогда так получается:
class House:
houses_history = []
def __new__(cls, *args, **kwargs):
cls.houses_history.append(args[0])
instance = object.__new__(cls) # добавили объект
return instance
def __init__(self, name, number_of_floors):
self.name = name
self.number_of_floors = number_of_floors
def __del__(self):
print(f'{self.name} снесён, но он останется в истории')
@classmethod # Декоратор
def get_houses_history(cls):
return cls.houses_history