Куда пропали sys.modules?

>>> import sys
>>> del sys.modules['sys']
>>> import sys
>>> sys.modules
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'sys' has no attribute 'modules'

Почему повторно импортированный модуль sys больше не имеет некоторых атрибутов?

Я использую Python 3.12.3, и это происходит в macOS, Linux и Windows. Это происходит как в REPL, так и в скрипте .py. Этого не происходит в Python 3.11.

Как, черт возьми, это вообще произошло? Я не могу это воспроизвести (python 3.9.16 и 3.11.0)

dragoncoder047 03.05.2024 21:24

@dragoncoder047 Для меня это невозможно было воспроизвести в модуле, но оно было внутри REPL. (у меня 3.12)

S.B 03.05.2024 21:25

Это не нормальное поведение для всех модулей. В частности, с sys должна быть какая-то скрытая работа. Я не знаю, почему

S.B 03.05.2024 21:30

Вероятно, есть что-то особенное в том, как REPL управляет своим пространством имен, которое отличается от того, как работают обычные файловые пространства имен при запуске сценариев.

Barmar 03.05.2024 21:30

В Python есть несколько специальных модулей, например builtins. sys также может получить специальное лечение.

Barmar 03.05.2024 21:32

Я могу воспроизвести это в скрипте и на REPL 3.12.3. Я тоже пробовал 3.11-3.8.

wjandrea 03.05.2024 21:54

Дело не в одном, похоже, что около половина всех атрибутов теряется таким образом.

no comment 03.05.2024 21:54

Похоже, что некоторые атрибуты модуля sys не определены стандартным способом (github.com/python/cpython/blob/… ). Например. атрибут «modules» добавляется только при инициализации интерпретатора ( github.com/python/cpython/blob/…)

Andrej Kesely 03.05.2024 22:24

Я не могу воспроизвести это в Windows ни с помощью командной строки, ни с помощью IDLE (3.11.0), ни с помощью командной строки WSL2 Ubuntu (3.8.10).

Mark Ransom 06.05.2024 20:10

@MarkRansom Попробуйте 3.12

no step on snek 06.05.2024 22:12

«Доктор, мне больно, когда я это делаю!» «Не делай этого» — есть ли код, который можно было бы написать в реальной среде, где это когда-либо произойдет?

Charles Duffy 06.05.2024 22:17

@CharlesDuffy Это не имеет отношения к вопросу «почему это происходит».

no step on snek 06.05.2024 22:19

@nosteponsnek, но это имеет отношение к вопросу: «Почему это происходит?» здесь вообще по теме. Вопросы должны носить практический характер.

Charles Duffy 06.05.2024 23:17

См. также: Meta Stack Exchange , В чем смысл закрывающих вопросов «почему» в языковом дизайне? -- это не вопрос о языковом дизайне как таковой, но точно так же нельзя разумно ожидать, что на него будет ответ, который изменит подход к практике разработки программного обеспечения.

Charles Duffy 06.05.2024 23:20

То, как инициализируется sys, определенно является темой для [python-internals] («Как Python работает под капотом?»).

jfs 07.05.2024 09:19

@CharlesDuffy Понимая режим сбоя, вы сможете лучше понять, когда/почему/как перезагрузка модуля может оказаться ненадежной. Я думаю, что это хорошие практические знания.

no step on snek 08.05.2024 21:54
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
8
16
163
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Совершенно очевидно, что вам не следует этого делать, поскольку это, естественно, может привести к поломке чего-либо. В реализации Python, которую вы пробовали, случаются поломки именно таким образом, но Python не обещает, что произойдет. Большая часть того, что я собираюсь сказать, — это детали реализации.


Модуль sys нельзя инициализировать, как обычные встроенные модули, поскольку он отвечает за большую часть основных функций. Вместо этого при запуске интерпретатора Python создает модуль sys со специальной функцией _PySys_Create. Эта функция отвечает (частично) за правильную настройку модуля sys, включая атрибут sys.modules:

    if (PyDict_SetItemString(sysdict, "modules", modules) < 0) {
        goto error;
    }

Когда вы это сделаете del sys.modules['sys'], система импорта потеряет модуль sys. Когда вы пытаетесь импортировать его снова, Python пытается создать совершенно новый модуль sys, и он делает это так, как если бы sys был обычным встроенным модулем. Проходит процедуру инициализации обычных встроенных модулей. Эта процедура оставляет новый модуль sys в противоречивом, неправильно инициализированном состоянии, поскольку sys никогда не предназначался для инициализации таким способом.

Есть поддержка перезагрузки sys, хотя я думаю, что команда разработчиков подумывает о том, чтобы отказаться от этой поддержки — варианты использования очень неясны, и единственный, который мне приходит в голову, устарел. Часть повторной инициализации заканчивается тем, что попадает в путь кода , предназначенный для перезагрузки sys, который обновляет свой __dict__ из копии, созданной в начале исходной инициализации sys, прямо перед установкой sys.modules:

    interp->sysdict_copy = PyDict_Copy(sysdict);
    if (interp->sysdict_copy == NULL) {
        goto error;
    }

    if (PyDict_SetItemString(sysdict, "modules", modules) < 0) {
        goto error;
    }

Эта копия обрабатывается по-другому в более ранних версиях Python, отсюда и различия в поведении, связанные с версией.

Но _PySys_Create был и в версии 3.11. Что изменилось в 3.12?

no step on snek 06.05.2024 22:47

@nosteponsnek: Ответ расширен.

user2357112 06.05.2024 23:10

Другие вопросы по теме