6.4. 使用 sys.modules

与 Python 中的所有其他内容一样,模块也是对象。导入后,您始终可以通过全局字典 sys.modules 获取对模块的引用。

示例 6.12. 介绍 sys.modules

>>> import sys                          1
>>> print '\n'.join(sys.modules.keys()) 2
win32api
os.path
os
exceptions
__main__
ntpath
nt
sys
__builtin__
site
signal
UserDict
stat
1 sys 模块包含系统级信息,例如您正在运行的 Python 版本(sys.version 或 sys.version_info),以及系统级选项,例如允许的最大递归深度(sys.getrecursionlimit() 和 sys.setrecursionlimit())。
2 sys.modules 是一个字典,其中包含自 Python 启动以来已导入的所有模块;键是模块名称,值是模块对象。请注意,这不仅仅是您的程序导入的模块。Python 在启动时会预加载一些模块,如果您使用的是 Python IDE,则 sys.modules 包含您在 IDE 中运行的所有程序导入的所有模块。

此示例演示如何使用 sys.modules。

示例 6.13. 使用 sys.modules

>>> import fileinfo         1
>>> print '\n'.join(sys.modules.keys())
win32api
os.path
os
fileinfo
exceptions
__main__
ntpath
nt
sys
__builtin__
site
signal
UserDict
stat
>>> fileinfo
<module 'fileinfo' from 'fileinfo.pyc'>
>>> sys.modules["fileinfo"] 2
<module 'fileinfo' from 'fileinfo.pyc'>
1 导入新模块时,它们会被添加到 sys.modules 中。这解释了为什么两次导入同一个模块的速度非常快:Python 已经在 sys.modules 中加载并缓存了该模块,因此第二次导入只是一个字典查找。
2 给定任何先前导入的模块的名称(作为字符串),您可以通过 sys.modules 字典获取对模块本身的引用。

下一个示例演示如何将 __module__ 类属性与 sys.modules 字典一起使用,以获取对定义类的模块的引用。

示例 6.14. __module__ 类属性

>>> from fileinfo import MP3FileInfo
>>> MP3FileInfo.__module__              1
'fileinfo'
>>> sys.modules[MP3FileInfo.__module__] 2
<module 'fileinfo' from 'fileinfo.pyc'>
1 每个 Python 类都有一个内置的类属性 __module__,它是定义该类的模块的名称。
2 将其与 sys.modules 字典结合使用,您可以获取对定义类的模块的引用。

现在,您准备好在第 5 章中介绍的示例程序 fileinfo.py 中查看如何使用 sys.modules。此示例显示了代码的那一部分。

示例 6.15. sys.modules 在 fileinfo.py

    def getFileInfoClass(filename, module=sys.modules[FileInfo.__module__]):       1
        "get file info class from filename extension"                             
        subclass = "%sFileInfo" % os.path.splitext(filename)[1].upper()[1:]        2
        return hasattr(module, subclass) and getattr(module, subclass) or FileInfo 3
1 这是一个有两个参数的函数;filename 是必需的,但 module可选的,默认为包含 FileInfo 类的模块。这看起来效率低下,因为您可能希望 Python 每次调用该函数时都计算 sys.modules 表达式。实际上,Python 只在第一次导入模块时计算一次默认表达式。您稍后会看到,您永远不会使用 module 参数调用此函数,因此 module 充当函数级常量。
2 在深入了解 os 模块之后,您将仔细研究这一行。现在,请相信 subclass 最终会成为一个类的名称,例如 MP3FileInfo
3 您已经了解了getattr,它通过名称获取对对象的引用。hasattr 是一个补充函数,用于检查对象是否具有特定属性;在本例中,是检查模块是否具有特定类(尽管它适用于任何对象和任何属性,就像 getattr 一样)。用中文来说,这行代码的意思是:“如果此模块具有 subclass 命名的类,则返回它,否则返回基类 FileInfo

模块的进一步阅读