Метод __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