Я читаю код Есть класс, в котором __del__
метод __del__
. Я понял, что этот метод используется для уничтожения экземпляра класса. Тем не менее, я не могу найти место, где этот метод используется. Основная причина этого заключается в том, что я не знаю, как используется этот метод, вероятно, не так: obj1.del()
. Итак, мои вопросы, как вызвать метод __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
Ответ 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__
автоматически вызывается при выходе из него. Смотрите этот вопрос для более подробной информации.