Найти тему
Машинное обучение

❌ Деструктор __del__

(часто спрашивают на собеседованиях)

Этот магический метод позволяет определить поведение экземпляра пользовательского типа при готовности интерпретатора уничтожить его.

Многие думают, что del x вызывает метод x.__del__. Это неправда. Python использует механизм подсчета ссылок, и del x – лишь один из способов уменьшить количество ссылок на 1.

📎 Примеры. Определим такой класс, где будем следить за вызовом его метода __del__:

class Bazooka:

  def __del__(self):

    print('Bazooka.__del__()')

>>> b = Bazooka()  # тут мы привяжем новый объект Bazooka() к имени переменной b (1 ссылка)

>>> del b      # тут мы удаляем имя b, объект отвязывется, ссылок - 0, вызывается деструктор.

Bazooka.__del__()

>>> b = Bazooka()

>>> b = None    # имя b не удалено, но объект будет отвязан от него и деструктор вызовется

Bazooka.__del__()

>>> b = Bazooka()

>>> b2 = b     # объект привязан и к b, и к b2 (ссылок - 2)

>>> del b      # удаляем первый, ссылок - 1, деструктор не вызван

>>> del b2     # удаляем второй, ссылок - 0, деструктор вызывается

Bazooka.__del__()

Важные нюансы:

❗️ Не гарантируется, что метод будет вызван для объектов, всё ещё существующих на момент выхода интерпретатора.

❗️#Если метод определён в базовом классе, то потомок должен вызывать его явно, чтобы удаление части экземпляра, реализуемой базовым классом произошло без ошибок.

❗️ Ссылка на объект может остаться при броске исключения в sys.exc_traceback (исправляется путем sys.last_traceback = None)

❗️ До Python 3.4 сборщик мусора не мог разорвать циклические ссылки с объектами, у которых определен __del__.

❗️ Не стоит путать __del__ и __delete__, __delete__ используется напрямую крайне редко, и нужен он для объектов-дескрипторов.