Почему в sys.modules есть фиктивные модули?
Импорт стандартного модуля "logging" загрязняет sys.modules с кучей фиктивных записей:
Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)] on win32
>>> import sys
>>> import logging
>>> sorted(x for x in sys.modules.keys() if 'log' in x)
['logging', 'logging.atexit', 'logging.cStringIO', 'logging.codecs',
'logging.os', 'logging.string', 'logging.sys', 'logging.thread',
'logging.threading', 'logging.time', 'logging.traceback', 'logging.types']
# and perhaps even more surprising:
>>> import traceback
>>> traceback is sys.modules['logging.traceback']
False
>>> sys.modules['logging.traceback'] is None
True
Таким образом, импорт этого пакета добавляет дополнительные имена в sys.modules, за исключением того, что они не являются модулями, а просто ссылаются на None. У других модулей (например, xml.dom и encodings) есть эта проблема. Почему?
Изменить: На основе ответа bobince есть страницы, описывающие источник (см. раздел "Манекены в sys.modules" ) и будущее этой функции.
Ответы
Ответ 1
None
значения в sys.modules
являются кэшированными отказами относительного поиска.
Итак, когда вы находитесь в пакете foo
, а вы import sys
, Python сначала ищет модуль foo.sys
, и если это не удается, то он выходит на модуль верхнего уровня sys
. Чтобы избежать необходимости снова проверять файловую систему для foo/sys.py
при дальнейшем относительном импорте, он сохраняет None
в sys.modules
, чтобы флаг, что модуль не существовал, и последующий импорт не должен выглядеть там снова, но идти прямо к загруженному sys
.
Это деталь реализации cPython, на которую нельзя положительно полагаться, но вам нужно будет знать ее, если вы делаете неприятный махический импорт/перезагрузку.
Это происходит со всеми пакетами, а не только с logging
. Например, import xml.dom
и см. xml.dom.xml
в списке модулей, поскольку он пытается импортировать xml
изнутри xml.dom
.
Поскольку Python движется к абсолютному импорту, это уродство будет меньше.
Ответ 2
Я не уверен, почему это происходит, но encodings
показывает те же ссылки на None
.
Python 2.6.2 (r262:71600, May 24 2009, 00:12:54)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> for n in filter(lambda x: x.startswith('encodings'), sys.modules):
... print n, type(sys.modules[n])
...
encodings <type 'module'>
encodings.encodings <type 'NoneType'>
encodings.codecs <type 'NoneType'>
encodings.__builtin__ <type 'NoneType'>
encodings.utf_8 <type 'module'>
encodings.aliases <type 'module'>
Я не знаю, что происходит с некоторыми элементами, которые являются None
, но я могу сказать, что он не уникален для модуля logging
.