Ответ 1
TL; DR: это старая проблема в CPython, которая была окончательно исправлена в CPython 3.4. Объекты, хранящиеся в режиме реального времени по ссылочным циклам, на которые ссылаются глобальные модули модуля, не были должным образом завершены на выходе интерпретатора в версиях CPython до 3.4. Классы нового стиля имеют неявные циклы в своих экземплярах type
; классы старого стиля (типа classobj
) не имеют неявных эталонных циклов.
Несмотря на то, что в этом случае исправлено, документация CPython 3.4 по-прежнему рекомендует не зависеть от __del__
, который вызывается при выходе из интерпретатора - считайте себя предупреждала.
В классах нового стиля есть ссылочные циклы сами по себе: наиболее заметно
>>> class A(object):
... pass
>>> A.__mro__[0] is A
True
Это означает, что они не могут быть немедленно удалены *, но только при запуске сборщика мусора. Поскольку ссылка на них удерживается главным модулем, они остаются в памяти до выключения интерпретатора. В конце, во время очистки модуля, все глобальные имена модуля в основном настроены на None
, и в зависимости от того, какие объекты имели счетчики ссылок, уменьшились до нуля (например, старый стиль), также были удалены, Тем не менее, классы нового стиля, имеющие ссылочные циклы, не будут выпущены/завершены этим.
Циклический сборщик мусора не будет запускаться на выходе интерпретатора (что разрешено документацией CPython:
Не гарантируется, что методы
__del__()
вызываются для объектов, которые все еще существуют, когда переводчик завершает работу.
Теперь классы старого стиля в Python 2 не имеют неявных циклов. Когда код очистки/завершения модуля CPython устанавливает глобальные переменные в None
, остается только оставшаяся ссылка на класс B
; то B
удаляется, и последняя ссылка на a
отбрасывается, а также завершается a
.
Чтобы продемонстрировать тот факт, что классы нового стиля имеют циклы и требуют GC sweep, тогда как в классах старого стиля нет, вы можете попробовать следующую программу в CPython 2 (у CPython 3 нет классов старого стиля больше):
import gc
class A(object):
def __init__(self):
print("A init")
def __del__(self):
print("A del")
class B(object):
a = A()
del B
print("About to execute gc.collect()")
gc.collect()
С B
в качестве класса нового стиля, как указано выше, вывод
A init
About to execute gc.collect()
A del
С B
в качестве класса старого стиля (class B:
) вывод
A init
A del
About to execute gc.collect()
То есть класс нового стиля был удален только после gc.collect()
, хотя последняя внешняя ссылка на него уже была отброшена; но класс старого стиля был удален мгновенно.
Значительная часть этого уже исправлена в Python 3.4: благодаря PEP 442, который включал процедуру отключения модуля на основе кода GC. Теперь даже при выходе интерпретатора глобалы модуля завершаются с помощью обычной сборки мусора. Если вы запустите свою программу под Python 3.4, программа напечатает
A init
A del
В то время как с Python <= 3.3, он будет печатать
A init
( Обратите внимание на, что другие реализации по-прежнему могут или не могут выполнить __del__
в данный момент, независимо от версии их выше, на или ниже, 3.4)