Деструкторы классов вызываются в момент уничтожения объекта сборщиком мусора. В них помещают код, который необходим для корректного завершения работы объекта. Предположим есть такой код:
class FooType(object):
def __init__(self, id):
self.id = id
print self.id, 'born'
def __del__(self):
print self.id, 'died'
def make_foo():
print 'Making...'
ft = FooType(1)
print 'Returning...'
return ft
print 'Calling...'
ft = make_foo()
print 'End...'Он производит такой вывод:
Calling...
Making...
1 born
Returning...
End...
1 died
Как видим, все нормально. Но иногда с деструкторами бывают проблемы. Приведенный ниже код имеет циклическую ссылку:
class FooType(object):
def __init__(self, id, parent):
self.id = id
self.parent = parent
print 'Foo', self.id, 'born'
def __del__(self):
print 'Foo', self.id, 'died'
class BarType(object):
def __init__(self, id):
self.id = id
self.foo = FooType(id, self)
print 'Bar', self.id, 'born'
def __del__(self):
print 'Bar', self.id, 'died'
b = BarType(12)Здесь объект класса FooType является свойством объекта класса BarType и при этом он хранит ссылку на него. Если бы этой ссылки не было, то вызов деструтора BarType, приводил бы к вызову деструктора FooType. Но в нашей ситуации этого не происходит:
Foo 12 born
Bar 12 born
Официальная документация сообщает:
Циклические ссылки не могут быть обработаны сборщиком мусора, если только не используется __del__() метод уровня не Python-кода.
В таких случаях многие python-программисты часто добавляют дополнительные методы, вызов которых необходимо производить перед завершением работы с объектом. Но всегда есть опасность забыть о вызове такого метода. К счастью, есть способ решения этой проблемы с использованием деструкторов. Для этого ссылку на родительский объект в классе FooType необходимо сделать слабой (weak reference). Эту возможность предоставляет модуль weakref. Справка из документации:
Слабая ссылка на объект является не достаточным условием для поддержания жизни объекта. Если единственные оставшиеся ссылки являются слабыми, сборщик мусора произведет уничтожение объекта и освободит память. Основная польза слабых ссылок заключается в реализации кэша или отображения (mapping) крупных объектов, для поддержания функционирования которых недостаточно одного их наличия в кэше или отображении.
Ниже показан предыдущий пример с использованием weakref:
import weakref
class FooType(object):
def __init__(self, id, parent):
self.id = id
self.parent = weakref.ref(parent)
print 'Foo', self.id, 'born'
def __del__(self):
print 'Foo', self.id, 'died'
class BarType(object):
def __init__(self, id):
self.id = id
self.foo = FooType(id, self)
print 'Bar', self.id, 'born'
def __del__(self):
print 'Bar', self.id, 'died'
b = BarType(12)Теперь все работает так как надо:
Foo 12 born
Bar 12 born
Bar 12 died
Foo 12 died
(Перевод статьи: http://eli.thegreenplace.net/2009/06/12/safely-using-destructors-in-python)