Подтвердить что ты не робот

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

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

4b9b3361

Ответ 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  

Ответ 2

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

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

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

Не используйте __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__, игнорируются.
  • __del__ дополняет __new__ гораздо больше, чем __init__. Это сбивает с толку. См http://www.algorithm.co.il/blogs/programming/python-gotchas-1- дель -is-не-заместитель напротив посещающих инициализации/ для объяснения и подводных камней.
  • __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__ означает, что вы не забываете вызывать __del__ выражение. См http://eli.thegreenplace.net/2009/06/12/safely-using-destructors-in-python/ для про __del__ точки зрения. Обычно речь идет об освобождении ctypes или какого-либо другого специального ресурса.

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

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

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

Ответ 3

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

del obj

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

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

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

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

Ответ 4

Метод __del__ (note spelling!) вызывается, когда ваш объект окончательно уничтожен. С технической точки зрения (в 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__ будет вызываться либо - интерпретатор может выйти разными способами, не удаляя все объекты.

Ответ 5

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