__del__является финализатором . Он вызывается, когда объект собирается сборщиком мусора, что происходит в какой-то момент после удаления всех ссылок на объект.
В простом случае это может быть сразу после того, как вы скажете, del xили, если xэто локальная переменная, после завершения функции. В частности, если нет циклических ссылок, CPython (стандартная реализация Python) немедленно выполняет сборку мусора.
Однако это деталь реализации CPython. Единственное обязательное свойство сборки мусора Python - это то, что это происходит после удаления всех ссылок, поэтому это может не происходить сразу после этого и может не произойти вообще .
Более того, переменные могут существовать в течение длительного времени по многим причинам , например, распространяющееся исключение или самоанализ модуля могут поддерживать счетчик ссылок на переменную больше 0. Кроме того, переменная может быть частью цикла ссылок - CPython с включенной сборкой мусора чаще всего ломается. , но не все, такие циклы, да и то только периодически.
Поскольку у вас нет гарантии, что он будет выполнен, никогда не следует помещать код, который вам нужно запустить __del__()- вместо этого этот код принадлежит finallyпредложению tryблока или диспетчеру контекста в withоператоре. Тем не менее, существуют действительные случаи использования для __del__: например , если объект Xссылки , Yа также хранит копию Yсправки в глобальном cache( cache['X -> Y'] = Y) , то это было бы вежливой для X.__del__также удалить запись кэша.
Если вы знаете , что деструктор обеспечивает (в нарушение указанного выше ориентира) требуемой очистки, вы можете назвать это непосредственно , так как нет ничего особенного, как метод: x.__del__(). Очевидно, вам следует делать это только в том случае, если вы знаете, что он не против, когда вам дважды позвонят. Или, в крайнем случае, вы можете переопределить этот метод, используя
type(x).__del__ = my_safe_cleanup_method