6.4. 使用 sys.modules
Description: Python from novice to pro
Keywords: Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free

# 深入 Python :Dive Into Python 中文版 Python 从新手到专家 [Dip_5.4b_CPyUG_Release] | Find:

## 6.4. 使用 ``sys`.modules`

与其它任何 Python 的东西一样，模块也是对象。只要导入了，总可以用全局 dictionary ``sys`.modules` 来得到一个模块的引用。

### 例 6.12. ``sys`.modules` 介绍

    >>> import sys
    >>> print '\n'.join(sys.modules.keys())
    win32api
    os.path
    os
    exceptions
    __main__
    ntpath
    nt
    sys
    __builtin__
    site
    signal
    UserDict
    stat

| `sys` 模块包含了系统级的信息，像正在运行的 Python 的版本 (``sys`.version` 或 ``sys`.version_info`)，和系统级选项，像最大允许递归的深度 (``sys`.getrecursionlimit()` 和 ``sys`.setrecursionlimit()`)。
| ``sys`.modules` 是一个字典，它包含了从 Python 开始运行起，被导入的所有模块。键字就是模块名，键值就是模块对象。请注意除了你的程序导入的模块外还有其它模块。Python 在启动时预先装入了一些模块，如果你在一个 Python IDE 环境下，``sys`.modules` 包含了你在 IDE 中运行的所有程序所导入的所有模块。

下面的例子展示了如何使用 ``sys`.modules`。

### 例 6.13. 使用 ``sys`.modules`

    >>> import fileinfo
    >>> 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"]
    <module 'fileinfo' from 'fileinfo.pyc'>

| 当导入新的模块，它们加入到 ``sys`.modules` 中。这就解释了为什么第二次导入相同的模块时非常的快：Python 已经在 ``sys`.modules` 中装入和缓冲了，所以第二次导入仅仅对字典做了一个查询。
| 一旦给出任何以前导入过的模块名 (以字符串方式)，通过 ``sys`.modules` 字典，你可以得到对模块本身的一个引用。

下面的例子将展示通过结合使用 `__module__` 类属性和 ``sys`.modules` dictionary 来获取已知类所在的模块。

### 例 6.14. `__module__` 类属性

    >>> from fileinfo import MP3FileInfo
    >>> MP3FileInfo.__module__
    'fileinfo'
    >>> sys.modules[MP3FileInfo.__module__]
    <module 'fileinfo' from 'fileinfo.pyc'>

| 每个 Python 类都拥有一个内置的类属性 `__module__`，它定义了这个类的模块的名字。
| 将它与 ``sys`.modules` 字典复合使用，你可以得到定义了某个类的模块的引用。

现在准备好了，看看在样例程序 第 5 章 ``sys`.modules` 介绍的 `fileinfo.py` 中是如何使用的。这个例子显示它的一部分代码。

### 例 6.15. `fileinfo.py` 中的 ``sys`.modules`

        def getFileInfoClass(filename, module=sys.modules[FileInfo.__module__]):
            "get file info class from filename extension"
            subclass = "%sFileInfo" % os.path.splitext(filename)[1].upper()[1:]
            return hasattr(module, subclass) and getattr(module, subclass) or FileInfo

| 这是一个有两个参数的函数；`filename` 是必须的，但 `module` 是可选的并且 module 的缺省值包含了 `FileInfo` 类。这样看上去效率低，因为你可能认为 Python 会在每次函数调用时计算这个 ``sys`.modules` 表达式。实际上，Python 仅会对缺省表达式计算一次，是在模块导入的第一次。正如后面我们会看到的，我们永远不会用一个 `module` 参数来调用这个函数，所以 `module` 的功能是作为一个函数级别的常量。
| 我们会在后面再仔细研究这一行，在我们了解了 `os` 模块之后。那么现在，只要相信 `subclass` 最终为一个类的名字就行了，像 `MP3FileInfo`。
| 你已经了解了 `getattr`，它可以通过名字得到一个对象的引用。`hasattr` 是一个补充性的函数，用来检查一个对象是否具有一个特定的属性；在本例中，用来检查一个模块是否有一个特别的类 (然而它可以用于任何类和任何属性，就像 `getattr`)。用英语来说，这行代码是说，“If this module has the class named by `subclass` then return it, otherwise return the base class `FileInfo` (如果这个模块有一个名为 `subclass` 的类，那么返回它，否则返回基类 `FileInfo`)”。

### 进一步阅读

- Python Tutorial 讨论了缺省参数到底在什么时候和是如何计算的。
- Python Library Reference 提供了 `sys` 模块的文档。