6.6. 整合所有内容

现在,所有的多米诺骨牌都已就位。您已经看到了每一行代码是如何工作的。现在让我们退后一步,看看它们是如何组合在一起的。

示例 6.21. listDirectory


def listDirectory(directory, fileExtList):                                         1
    "get list of file info objects for files of particular extensions"
    fileList = [os.path.normcase(f)
                for f in os.listdir(directory)]           
    fileList = [os.path.join(directory, f) 
               for f in fileList
                if os.path.splitext(f)[1] in fileExtList]                          2
    def getFileInfoClass(filename, module=sys.modules[FileInfo.__module__]):       3
        "get file info class from filename extension"                             
        subclass = "%sFileInfo" % os.path.splitext(filename)[1].upper()[1:]        4
        return hasattr(module, subclass) and getattr(module, subclass) or FileInfo 5
    return [getFileInfoClass(f)(f) for f in fileList]                              6
1 listDirectory 是整个模块的重头戏。它接受一个目录(例如,在我的例子中是 c:\music\_singles\)和一个感兴趣的文件扩展名列表(例如 ['.mp3']),并返回一个类实例列表,这些实例的行为类似于字典,其中包含有关该目录中每个感兴趣文件的元数据。而且它只用了几行简单的代码就完成了。
2 正如您在上一节中看到的,这行代码获取 directory 中所有具有感兴趣文件扩展名(由 fileExtList 指定)的文件的完整路径名列表。
3 老派的 Pascal 程序员可能很熟悉它们,但当我告诉大多数人 Python 支持 嵌套函数(实际上是一个函数中的函数)时,他们都会一脸茫然。嵌套函数 getFileInfoClass 只能从定义它的函数 listDirectory 中调用。与任何其他函数一样,您不需要接口声明或任何花哨的东西;只需定义函数并编写代码即可。
4 现在您已经了解了 os 模块,这行代码应该更容易理解了。它获取文件的扩展名(os.path.splitext(filename)[1]),将其强制转换为大写(.upper()),切掉点([1:]),并使用字符串格式化从中构造一个类名。因此,c:\music\ap\mahadeva.mp3 变为 .mp3,再变为 .MP3,再变为 MP3,最后变为 MP3FileInfo
5 在构造了处理该文件的处理程序类的名称后,您需要检查该处理程序类是否确实存在于此模块中。如果存在,则返回该类,否则返回基类 FileInfo。这是一个非常重要的点:此函数返回一个类。不是类的实例,而是类本身。
6 对于“感兴趣的文件”列表(fileList)中的每个文件,您都使用文件名(f)调用 getFileInfoClass。调用 getFileInfoClass(f) 会返回一个类;您不知道具体是哪个类,但您也不关心。然后,您创建此类(无论是什么类)的实例,并将文件名(f)再次传递给 __init__ 方法。正如您在本章前面看到的,FileInfo__init__ 方法设置 self["name"],这会触发 __setitem__,后者在后代(MP3FileInfo)中被覆盖,以适当地解析文件以提取文件的元数据。您对每个感兴趣的文件都执行此操作,并返回结果实例的列表。

请注意,listDirectory 是完全通用的。它事先不知道它将获取哪些类型的文件,或者定义了哪些类可以潜在地处理这些文件。它会检查目录以查找要处理的文件,然后内省其自身模块以查看定义了哪些特殊的处理程序类(例如 MP3FileInfo)。您可以通过定义一个名称合适的类来扩展此程序以处理其他类型的文件:HTMLFileInfo 用于 HTML 文件,DOCFileInfo 用于 Word .doc 文件,等等。listDirectory 将处理所有这些文件,而无需修改,方法是将实际工作交给适当的类并整理结果。