Ответ 1
Поведение плохо документировано и присутствует во всех версиях Python примерно с 1,5-и до тех пор, пока Python 3.4:
Как часть этого изменения, глобальные глобальные модули больше не принудительно устанавливаются на
None
во время остановки интерпретатора в большинстве случаев, вместо этого полагаясь на обычную работу циклического сборщика мусора.
Единственной документацией для поведения является moduleobject.c
исходный код:
/* To make the execution order of destructors for global
objects a bit more predictable, we first zap all objects
whose name starts with a single underscore, before we clear
the entire dictionary. We zap them by replacing them with
None, rather than deleting them from the dictionary, to
avoid rehashing the dictionary (to some extent). */
Обратите внимание, что установка значений None
является оптимизацией; альтернативой будет удаление имен из сопоставления, что приведет к различным ошибкам (NameError
исключения, а не AttributeError
при попытке использовать глобальные переменные из обработчика __del__
).
Как вы узнали в списке рассылки, поведение предшествует циклическому сборщику мусора; это было добавлено в 1998 году, в то время как циклический сборщик мусора был добавлен в 2000 году. Поскольку объектные объекты всегда ссылаются на модуль __dict__
, все объекты функции в модуле связаны с круговыми ссылками, поэтому требуется перед тем, как GC начнет играть.
Он поддерживался на месте, даже когда был добавлен циклический GC, поскольку в цикле могут быть объекты с __del__
. Эти не могут собирать мусор, а очистка словаря модуля, по крайней мере, приведет к удалению модуля __dict__
из таких циклов. Не делая этого, все ссылки на глобальные модули этого модуля будут сохранены.
Изменения, сделанные для PEP 442, теперь позволяют сборщику мусора очищать циклические ссылки с объектами, которые предоставляют финализатор __del__
, устраняя необходимость очистки модуль __dict__
для большинства случаев. Код все еще существует, но это срабатывает только в том случае, если атрибут __dict__
еще сохраняется даже после перемещения содержимого sys.modules
на слабые ссылки и запуск коллекции GC запускать, когда интерпретатор выключается; модуль-финализатор модуля просто уменьшает счетчик ссылок.