Skip to main content
 首页 » 编程设计

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

2025年05月04日7exmyth

导入标准的“日志记录”模块会用一堆虚拟条目污染 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 和编码)也有这个问题。为什么?

编辑:在 bobince 的回答的基础上,有描述 the origin 的页面(参见“sys.modules 中的虚拟条目”部分)和 future的特征。

请您参考如下方法:

sys.modules 中的

None 值是相对查找的缓存失败。

所以当你在包 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 转向绝对导入,这种丑陋的事情会越来越少。