Факт 1
Методы экземпляра обычно хранятся в классе .Интерпретатор сначала ищет их в экземпляре __dict__
, который завершается ошибкой, а затем просматривает класс, который завершается успешно.
Когда вы динамически устанавливаете метод экземпляра A
в __init__
, вы создаетессылка на него в словаре экземпляра.Эта ссылка является циклической, поэтому счетчик ссылок никогда не обнулится, и счетчик ссылок не очистит A
up.
>>> class A(object):
... def _test(self): pass
... def __init__(self):
... self.test = self._test
...
>>> a = A()
>>> a.__dict__['test'].im_self
Fact 2
Сборщик мусора - это то, что Python использует дляиметь дело с циркулярными ссылками.К сожалению, он не может обрабатывать объекты с помощью __del__
методов, поскольку в целом он не может определить безопасный порядок их вызова.Вместо этого он просто помещает все такие объекты в gc.garbage
.Затем вы можете пойти посмотреть, чтобы разорвать циклы, чтобы они могли быть освобождены.Из документов
gc.garbage
Список объектов, для которых сборщик обнаружил, что они недоступны, но не могут быть освобождены (объекты, которые нельзя собрать).По умолчанию этот список содержит только объекты с __del__()
методами.Объекты, которые имеют __del__()
методы и являются частью эталонного цикла, приводят к невозможности сбора всего эталонного цикла, включая объекты не обязательно в цикле, но достижимые только из него.Python не собирает такие циклы автоматически, потому что, как правило, Python не может угадать безопасный порядок запуска методов __del__()
.Если вы знаете безопасный порядок, вы можете форсировать проблему, изучая список мусора и явно прерывая циклы из-за ваших объектов в списке.Обратите внимание, что эти объекты остаются живыми даже благодаря тому, что находятся в списке мусора, поэтому их также следует удалять из мусора.Например, после прерывания цикла выполните del gc.garbage[:]
, чтобы очистить список.Как правило, лучше избегать этой проблемы, не создавая циклы, содержащие объекты с методами __del__()
, и в этом случае можно проверить garbage
, чтобы убедиться, что такие циклы не создаются.
Следовательно
Не создавайте циклические ссылки на объекты с помощью методов __del__
, если вы хотите, чтобы они собирались мусором.