你现在位于:首页 > 深入 Python > 函数式编程 > 整合所有内容 | << >> | ||||
深入 Python从 Python 新手到专家 |
你现在已经学习了足够多的知识,可以解析本章代码示例的前七行:读取目录并导入其中的选定模块。
def regressionTest(): path = os.path.abspath(os.path.dirname(sys.argv[0])) files = os.listdir(path) test = re.compile("test\.py$", re.IGNORECASE) files = filter(test.search, files) filenameToModuleName = lambda f: os.path.splitext(f)[0] moduleNames = map(filenameToModuleName, files) modules = map(__import__, moduleNames) load = unittest.defaultTestLoader.loadTestsFromModule return unittest.TestSuite(map(load, modules))
让我们逐行、交互式地查看它。假设当前目录是 c:\diveintopython\py,其中包含本书附带的示例,包括本章的脚本。正如你在 16.2 节 “查找路径” 中看到的,脚本目录将位于 path 变量中,所以让我们从硬编码开始,然后继续。
>>> import sys, os, re, unittest >>> path = r'c:\diveintopython\py' >>> files = os.listdir(path) >>> files['BaseHTMLProcessor.py', 'LICENSE.txt', 'apihelper.py', 'apihelpertest.py', 'argecho.py', 'autosize.py', 'builddialectexamples.py', 'dialect.py', 'fileinfo.py', 'fullpath.py', 'kgptest.py', 'makerealworddoc.py', 'odbchelper.py', 'odbchelpertest.py', 'parsephone.py', 'piglatin.py', 'plural.py', 'pluraltest.py', 'pyfontify.py', 'regression.py', 'roman.py', 'romantest.py', 'uncurly.py', 'unicode2koi8r.py', 'urllister.py', 'kgp', 'plural', 'roman', 'colorize.py']
>>> test = re.compile("test\.py$", re.IGNORECASE)>>> files = filter(test.search, files)
>>> files
['apihelpertest.py', 'kgptest.py', 'odbchelpertest.py', 'pluraltest.py', 'romantest.py']
>>> filenameToModuleName = lambda f: os.path.splitext(f)[0]>>> filenameToModuleName('romantest.py')
'romantest' >>> filenameToModuleName('odchelpertest.py') 'odbchelpertest' >>> moduleNames = map(filenameToModuleName, files)
>>> moduleNames
['apihelpertest', 'kgptest', 'odbchelpertest', 'pluraltest', 'romantest']
![]() |
正如你在 4.7 节 “使用 lambda 函数” 中看到的,lambda 是一种快速创建内联、单行函数的方法。这个函数接受一个带扩展名的文件名,并使用你在 示例 6.17 “拆分路径名” 中看到的标准库函数 os.path.splitext 返回文件名部分。 |
![]() |
filenameToModuleName 是一个函数。与使用 def 语句定义的常规函数相比,lambda 函数没有什么神奇之处。你可以像调用任何其他函数一样调用 filenameToModuleName 函数,它会完全按照你的意愿执行操作:从其参数中删除文件扩展名。 |
![]() |
现在,你可以使用 map 将此函数应用于单元测试文件列表中的每个文件。 |
![]() |
结果正是你想要的:一个模块列表,以字符串形式表示。 |
>>> modules = map(__import__, moduleNames)>>> modules
[<module 'apihelpertest' from 'apihelpertest.py'>, <module 'kgptest' from 'kgptest.py'>, <module 'odbchelpertest' from 'odbchelpertest.py'>, <module 'pluraltest' from 'pluraltest.py'>, <module 'romantest' from 'romantest.py'>] >>> modules[-1]
<module 'romantest' from 'romantest.py'>
![]() |
正如你在 16.6 节 “动态导入模块” 中看到的,你可以使用 map 和 __import__ 的组合将模块名列表(作为字符串)映射到实际模块(你可以像任何其他模块一样调用或访问它们)。 |
![]() |
modules 现在是一个模块列表,可以像任何其他模块一样完全访问。 |
![]() |
列表中的最后一个模块是 romantest 模块,就像你说了 import romantest 一样。 |
>>> load = unittest.defaultTestLoader.loadTestsFromModule >>> map(load, modules)[<unittest.TestSuite tests=[ <unittest.TestSuite tests=[<apihelpertest.BadInput testMethod=testNoObject>]>, <unittest.TestSuite tests=[<apihelpertest.KnownValues testMethod=testApiHelper>]>, <unittest.TestSuite tests=[ <apihelpertest.ParamChecks testMethod=testCollapse>, <apihelpertest.ParamChecks testMethod=testSpacing>]>, ... ] ] >>> unittest.TestSuite(map(load, modules))
![]()
这个内省过程是 unittest 模块通常为我们做的事情。还记得我们各个测试模块用来启动整个过程的神奇的 unittest.main() 函数吗?unittest.main() 实际上创建了一个 unittest.TestProgram 的实例,该实例又创建了一个 unittest.defaultTestLoader 的实例,并将其加载到调用它的模块中。(如果 你没有给它一个引用,它如何获得对调用它的模块的引用?通过使用同样神奇的 __import__('__main__') 命令,它动态地导入当前运行的模块。我可以写一本关于 unittest 模块中使用的所有技巧和技术的书,但我永远也写不完。)
<< 动态导入模块 |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
总结 >> |