Вопрос-Ответ

What is the __del__ method and how do I call it?

Что такое метод __del__ и как мне его вызвать?

Я видел класс, в котором определен __del__ метод. Этот метод используется для уничтожения экземпляра класса. Однако я не могу найти место, где используется этот метод. Как используется этот метод? Вот так: obj1.del()?.

Как мне вызвать __del__ метод?

Переведено автоматически
Ответ 1

__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

* Ссылка:


Подробности реализации CPython: В настоящее время CPython использует схему подсчета ссылок с (необязательно) отложенным обнаружением циклически связанного мусора, который собирает большинство объектов, как только они становятся недоступными [...] Другие реализации действуют по-другому, и CPython может измениться.


Ответ 2

Я написал ответ на другой вопрос, хотя это более точный вопрос для него.

Как работают конструкторы и деструкторы?

Вот немного самоуверенный ответ.

Не используйте __del__. Это не C ++ и не язык, созданный для деструкторов. __del__ Метод действительно должен быть удален в Python 3.x, хотя я уверен, что кто-нибудь найдет вариант использования, который имеет смысл. Если вам нужно использовать __del__, помните об основных ограничениях для http://docs.python.org/reference/datamodel.html:


  • __del__ вызывается, когда сборщик мусора случайно собирает объекты, а не когда вы теряете последнюю ссылку на объект и не при выполнении del object.

  • __del__ отвечает за вызов any __del__ в суперклассе, хотя неясно, выполняется ли это в порядке разрешения метода (MRO) или просто вызывается каждый суперкласс.

  • Наличие __del__ означает, что сборщик мусора отказывается от обнаружения и очистки любых циклических ссылок, таких как потеря последней ссылки на связанный список. Вы можете получить список игнорируемых объектов из gc.garbage . Иногда вы можете использовать слабые ссылки, чтобы вообще избежать цикла. Это время от времени обсуждается: см. http://mail.python.org/pipermail/python-ideas/2009-October/006194.html.

  • __del__ Функция может обманывать, сохраняя ссылку на объект и останавливая сборку мусора.

  • Исключения, явно возникающие в __del__, игнорируются.

  • __del__ дополняет __new__ гораздо больше, чем __init__. Это сбивает с толку. Смотрите http://www.algorithm.co.il/blogs/programming/python-gotchas-1 -delне является противоположностью init/ для объяснения и подводных камней.

  • __del__ не является "любимым" дочерним элементом в Python. Вы заметите, что в документации sys.exit() не указано, собирается ли мусор перед завершением, и есть много странных проблем. Вызов __del__ для глобальных переменных вызывает проблемы со странным порядком, например, http://bugs.python.org/issue5099. Следует ли __del__ вызывать, даже если __init__ завершается неудачей? Смотрите http://mail.python.org/pipermail/python-dev/2000-March/thread.html#2423 Длинный поток.

Но, с другой стороны:


  • __del__ означает, что вы не забываете вызывать оператор close . Смотрите http://eli.thegreenplace.net/2009/06/12/safely-using-destructors-in-python / для получения профессиональной __del__ точки зрения. Обычно речь идет об освобождении ctypes или какого-либо другого специального ресурса.

И моя личная причина, по которой мне не нравится функция __del__.


  • Каждый раз, когда кто-то поднимает этот вопрос, __del__ это превращается в тридцать сообщений о путанице.

  • Он нарушает эти элементы в Zen of Python:

    • Простое лучше сложного.

    • Особые случаи недостаточно особенные, чтобы нарушать правила.

    • Ошибки никогда не должны передаваться молча.

    • Перед лицом двусмысленности откажитесь от искушения угадать.

    • Должен быть один – и предпочтительно только один - очевидный способ сделать это.

    • Если реализацию трудно объяснить, это плохая идея.


Итак, найдите причину не использовать __del__.

Ответ 3

Метод __del__, он будет вызван, когда объект будет собран из мусора. Обратите внимание, что его вызов не обязательно гарантируется. Следующий код сам по себе не обязательно это сделает.:

del obj

Причина в том, что del просто уменьшает количество ссылок на единицу. Если что-то еще имеет ссылку на объект, __del__ не будет вызвано.

Однако при использовании есть несколько предостережений__del__. Как правило, они просто не очень полезны. Для меня это больше похоже на то, что вы хотите использовать метод close или, возможно, оператор with.

Смотрите документацию python по __del__ методам.

Следует отметить еще одну вещь: __del__ методы могут препятствовать сборке мусора при чрезмерном использовании. В частности, циклическая ссылка, имеющая более одного объекта с __del__ методом, не будет собирать мусор. Это потому, что сборщик мусора не знает, какой из них вызывать первым. Смотрите Документацию по модулю gc для получения дополнительной информации.

Ответ 4

__del__ Метод (обратите внимание на орфографию!) вызывается, когда ваш объект окончательно уничтожен. С технической точки зрения (в CPython) это когда больше нет ссылок на ваш объект, т. Е. Когда он выходит за пределы области видимости.

Если вы хотите удалить свой объект и, таким образом, вызвать __del__ метод, используйте

del obj1

который удалит объект (при условии, что на него не было никаких других ссылок).

Я предлагаю вам написать небольшой класс, подобный этому

class T:
def __del__(self):
print "deleted"

И исследуйте в интерпретаторе python, например

>>> a = T()
>>> del a
deleted
>>> a = T()
>>> b = a
>>> del b
>>> del a
deleted
>>> def fn():
... a = T()
... print "exiting fn"
...
>>> fn()
exiting fn
deleted
>>>

Обратите внимание, что jython и ironpython имеют разные правила относительно того, когда именно объект удаляется и __del__ вызывается. Его использование не считается хорошей практикой __del__ хотя из-за этого и того факта, что объект и его окружение могут находиться в неизвестном состоянии при вызове. Также не совсем гарантировано, что он будет вызван __del__ - интерпретатор может завершить работу различными способами, не удаляя все объекты.

2023-12-31 08:23 python