为什么sys.modules中有虚拟模块?

Pet*_*sen 17 python import

导入标准的"日志记录"模块会使用一堆虚拟条目污染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
Run Code Online (Sandbox Code Playgroud)

因此,导入此包会将额外的名称添加到sys.modules中,除了它们不是模块,只是对None的引用.其他模块(例如xml.dom和编码)也有这个问题.为什么?

编辑:基于bobince的答案,有描述原点的页面(请参阅"sys.modules中的虚拟条目"部分)和该功能的未来.

bob*_*nce 23

None值in sys.modules是相对查找的缓存失败.

所以,当你和我一起打包fooimport sys,Python会首先查找一个foo.sys模块,如果失败则进入顶级sys模块.为了避免foo/sys.py在进一步的相对导入时再次检查文件系统,它会Nonesys.modulesto标记中存储该模块不存在,并且后续导入不应该再次查看,而是直接进入加载sys.

这是一个你无法有效依赖的cPython实现细节,但如果你正在进行令人讨厌的魔法导入/重载黑客攻击,你需要知道它.

它发生在所有包装上,而不仅仅是logging.例如,当它尝试从内部导入时,在模块列表中import xml.dom看到.xml.dom.xmlxmlxml.dom

随着Python走向绝对导入,这种丑陋将会发生.