Как я уже говорил, обычная причина для этого - кольца.
:
>>> class Parent(object):
... def __init__(self):
... self.children = []
... def add(self, ch):
... self.children.append(ch)
... ch.parent = self
...
>>> class Child(object):
... def __init__(self):
... self.parent = None
...
>>>
>>> p = Parent()
>>> p.add(Child())
>>> p
<__main__.Parent ...>
>>> p.children
[<__main__.Child ...>]
У нас получается кольцо: parent смотрит на child, а тот в свою очередь держит сильную ссылку на parent.
Объекты для удаления требуют пробежки gc (явной или отложенной-автоматической).
__del__ нельзя вставить ни в Parent ни в Child - gc не справится с освобождением.
Меняем код:
>>> class Child(object):
... def __init__(self):
... self._parent = None
... def _get_parent(self):
... return self._parent()
... def _set_parent(self, parent):
... self._parent = weakref.ref(parent)
... parent = property(_get_parent, _set_parent)
...
Теперь обратная ссылка получилась слабой (можно использовать еще и weakref.proxy, но мне привычней явное разыменование). Кольца нет, объекты удаляются по decref не попадая в garbage collector, методы __del__ будут вызываться, gc.collect не требуется - в общем, все счастливы.