3.13. More on modules

Modules, like everything else in Python, are objects. Once imported, you can always get a reference to a module through the global dictionary sys.modules.

Пример 3.31. Introducing 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 The sys module contains system-level information, like the version of Python you're running (sys.version or sys.version_info), and system-level options like the maximum allowed recursion depth (sys.getrecursionlimit() and sys.setrecursionlimit()).
2 sys.modules is a dictionary containing all the modules that have ever been imported since Python was started; the key is the module name, the value is the module object. Note that this is more than just the modules your program has imported. Python preloads some modules on startup, and if you're in a Python IDE, sys.modules contains all the modules imported by all the programs you've run within the IDE.

Пример 3.32. Using 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 As new modules are imported, they are added to sys.modules. This explains why importing the same module twice is very fast: Python has already loaded and cached the module in sys.modules, so importing the second time is simply a dictionary lookup.
2 Given the name (as a string) of any previously-imported module, you can get a reference to the module itself through the sys.modules dictionary.

Пример 3.33. The __module__ class attribute

>>> from fileinfo import MP3FileInfo
>>> MP3FileInfo.__module__              1
'fileinfo'
>>> sys.modules[MP3FileInfo.__module__] 2
<module 'fileinfo' from 'fileinfo.pyc'>
1 Every Python class has a built-in class attribute __module__, which is the name of the module in which the class is defined.
2 Combining this with the sys.modules dictionary, you can get a reference to the module in which a class is defined.

Пример 3.34. sys.modules in fileinfo.py

    def getFileInfoClass(filename, module=sys.modules[FileInfo.__module__]):       1
        "оределяет класс, предназначеный для обработки файла, по расширению"      
        subclass = "%sFileInfo" % os.path.splitext(filename)[1].upper()[1:]        2
        return hasattr(module, subclass) and getattr(module, subclass) or FileInfo 3
1 This is a function with two arguments; filename is required, but module is optional and defaults to the module which contains the FileInfo class. This looks inefficient, because you might expect Python to evaluate the sys.modules expression every time the function is called. In fact, Python only evaluates default expressions once, the first time the module is imported. As we'll see later, we never call this function with a module argument, so module serves as a function-level constant.
2 We'll plough through this line later, after we dive into the os module. For now, take it on faith that subclass ends up as the name of a class, like MP3FileInfo.
3 You already know about getattr, which gets a reference to an object by name. hasattr is a complementary function that checks whether an object has a particular attribute; in this case, whether a module has a particular class (although it works for any object and any attribute, just like getattr). In English, this line of code says “if this module has the class named by subclass then return it, otherwise return the base class FileInfo”.

Further reading