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

109

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

Вершина
источник

Ответы:

168

__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  
илья н.
источник
5
Вы говорите, что функция CPython по удалению объекта сразу после того, как его счетчик ссылок уменьшается до нуля, является «деталью реализации». Я не уверен. Можете ли вы предоставить ссылку, подтверждающую это утверждение? (Я имею в виду, жирный шрифт сам по себе довольно убедителен, но ссылки на втором месте ... :-)
Стюарт Берг
14
Детали реализации CPython: в настоящее время CPython использует схему подсчета ссылок с (необязательным) отложенным обнаружением циклически связанного мусора ... Другие реализации действуют иначе, и CPython может измениться. ( docs.python.org/2/reference/datamodel.html )
илья н.
Что __exit__в этом контексте? Это запускается после или до __del__или вместе?
lony
1
Включает ли фраза «может не произойти вообще», когда программа завершается?
Энди Хейден
1
@AndyHayden: __del__методы могут не работать даже при завершении программы, и даже когда они запускаются при завершении, написание __del__метода, который работает правильно, даже когда интерпретатор занят самоуничтожением вокруг вас, требует более тщательного кодирования, чем применяют многие программисты. (При очистке CPython __del__методы обычно запускаются при завершении работы интерпретатора, но бывают случаи, когда этого недостаточно. Потоки демонов, глобальные переменные уровня C и объекты, __del__созданные в другом, __del__могут привести к тому, что __del__методы не будут запущены.)
user2357112 поддерживает Моника
80

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

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

Вот несколько самоуверенный ответ.

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

  • __del__вызывается, когда сборщик мусора собирает объекты, а не когда вы теряете последнюю ссылку на объект и не выполняете del object.
  • __del__отвечает за вызов любого __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 -is-not-the-Against-of- init / для объяснения и ошибок.
  • __del__не является «любимым» ребенком Python. Вы заметите, что документация sys.exit () не указывает, собирается ли мусор перед выходом, и есть много странных проблем. Вызов __del__глобальных переменных on вызывает странные проблемы с упорядочением, например http://bugs.python.org/issue5099 . Следует __del__позвонить, даже если __init__не удалось? См. Http://mail.python.org/pipermail/python-dev/2000-March/thread.html#2423 для длинного потока.

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

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

И моя личная причина не любить эту __del__функцию.

  • Каждый раз, когда кто- __del__то вспоминает, это превращается в тридцать сообщений о замешательстве.
  • Он нарушает эти элементы в дзен Python:
    • Лучше простое, чем сложное.
    • Особых случаев недостаточно, чтобы нарушать правила.
    • Ошибки никогда не должны проходить незаметно.
    • Перед лицом двусмысленности откажитесь от соблазна угадать.
    • Должен быть один - а желательно только один - очевидный способ сделать это.
    • Если реализацию трудно объяснить, это плохая идея.

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

Чарльз Мерриам
источник
6
Даже если вопрос не совсем: почему не использовать __del__, а как звонить __del__, ваш ответ интересен.
nbro
Спасибо. Иногда лучшая идея - держаться подальше от ужасных идей.
Чарльз Мерриам
Из других новостей я забыл упомянуть, что PyPy (более быстрый интерпретатор для более длительных приложений) не работает на del .
Чарльз Мерриам
Спасибо @Gloin за обновление неработающей ссылки!
Чарльз Мерриам
@CharlesMerriam Благодарим Вас за ответ!
Том Берроуз
13

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

del obj

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

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

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

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

Джейсон Бейкер
источник
8

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

Ник Крейг-Вуд
источник
1
по сравнению с stackoverflow.com/a/2452895/611007 и stackoverflow.com/a/1481512/611007 , use del obj1кажется, плохая идея полагаться.
n611x007
0

Как уже упоминалось ранее, __del__функциональность несколько ненадежна. В случаях, когда это может показаться полезным, рассмотрите возможность использования вместо них методов __enter__и __exit__. Это даст поведение, подобное with open() as f: passсинтаксису, используемому для доступа к файлам. __enter__автоматически вызывается при входе в область видимости with, а __exit__вызывается автоматически при выходе из нее. См. Этот вопрос для получения более подробной информации.

Сомория
источник