Что такое метод __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__
- интерпретатор может завершить работу различными способами, не удаляя все объекты.