导航: 起始页 > Dive Into Python > 有效编程(Functional Programming) > 全部放在一起 | << >> | ||||
Python 研究(Dive Into Python)Python 从新手到高手 [DIP_5_4_CPUG_RELEASE] |
你已经学习了足够的知识,现在来分析本章范例代码的前七行:读取一个目录并从中导入选定的模块。
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 是一个函数。 lambda 与你以 def 语句定义的针对正则表达式的函数相比并不神奇。 你可以如其他函数一样的调用 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 | |
小结 >> |