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

时间:2009-12-24 13:58:47

标签: python import

导入标准的“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和编码)也有这个问题。为什么呢?

编辑:根据bobince的回答,有一些页面描述了the origin(请参阅“sys.modules中的虚拟条目”一节)和future的功能。

2 个答案:

答案 0 :(得分:23)

None中的

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

因此,当您在包fooimport sys中时,Python首先查找foo.sys模块,如果失败,则会查找顶级sys模块。为了避免在进一步的相对导入时再次检查文件系统foo/sys.py,它会在None中存储sys.modules以标记该模块不存在,并且后续导入不应该看起来再一次,但直接去加载sys

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

它适用于所有软件包,而不仅仅是logging。例如,import xml.dom并在尝试从xml.dom.xml内部导入xml时看到模块列表中的xml.dom

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

答案 1 :(得分:0)

我不确定为什么会这样,但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模块所独有的。