8-9<X16>regression.xml 函数编程
Contents
本章标题:存在多年的问题,Functional Programming 有效编程
函数编程
- “退化测试”和前面的“回归测试”都是好名字。我又一次把选择权交给了 Google……191,000 : 1,890,000,“回归测试”获胜。
“回归”是标准的数学用语(eg. linear regression,线性回归),而“退化”好像……
sample 一律译为“样例”。
- 原译“范例”,给人的感觉好像 Mark 写的程序就是样板了;
- 和前面章节一致。
为和前面章节一致,list comprehension 一律译为“列表解析”(原译“列表遍历”),list mapping 一律译为“列表映射”(原译“列表关联”)。
- 为和前面章节一致,标题中出现的“介绍XXX”一律改为“XXX介绍”。
- 频繁 typo:
倒入
导入
16.1 概览
Para 1:……你看到单元测试如何令大规模重组
变得容易
重构
Para 2:I actually use this script as part of the build process for this book; I have unit tests for several of the example programs
……实际上这是我构建本书自身代码的一部分。我为几个样例程序都编写了单元测试。
实际上这是本书的构建代码的一部分;……
例16.2上:把这段代码放在本书其他样例代码相同的目录下运行之,模块 test.py
中的所有单元测试将被找到并一起被运行。
moduletest.py
例16.2, (2):The next 5 tests are from...
接下来的五个代码来自于……测试
(3)中作类似修改。
16.2 找到路径
Para 1:从命令行运行 python 代码时,知道所运行代码所
在磁盘上的存储位置有时候是有必要的。
Para 2:This is one of those obscure little tricks that is virtually impossible to figure out on your own, but simple to remember once you see it. The key to it is sys.argv. As you saw in Chapter 9 XML Processing, this is a list that holds the list of command-line arguments. However, it also holds the name of the running script, exactly as it was called from the command line, and this is enough information to determine its location.
这是一个你很难自己弄明白,却一看到就会想起的小麻烦。核心功能来源于 sys.argv。正如你在 第 9 章 XML 处理 中看到的,它包含了很多命令行参数。当然就像从命令行中运行他们一样,它也同样记录了运行脚本的名字,这些信息足以令我们确定文件的位置。
这是一个不那么容易想起,但一想起就很容易解决的小麻烦。答案是 sys.argv。正如你在 第 9 章 XML 处理 中看到的,它包含了很多命令行参数。它也同样记录了运行脚本的名字,和你调用它时使用的命令一摸一样。这些信息足以令我们确定文件的位置。
后面多处作了与第二点类似的修改。
例16.3, (3):os.path.abspath 是这里的关键。它接受的路径名可以是部分的甚至是完全空白,却返回完整有效的路径名。
……但总能返回完整有效的路径名。
例16.4, (2):一个空字符串调用 os.path.abspath 当前的工作路径,与 os.getcwd()的效果相同。
用空字符串调用 os.path.abspath 将返回当前的工作路径,……
例16.5上:……这意味着如果你正工作于 /usr/ 目录,os.path.abspath('bin/../local/bin') 将会返回 /usr/local/bin。它以尽可能简单的方式格式化路径名。
它把路径名格式化为尽可能简单的形式。
例16.5, (2):如果脚本是以不完整路名被运行的,sys.argv[0] 还是会包含命令行中应
出现的一切。
Para -1:This technique will allow you to re-use this regression.py script on multiple projects. Just put the script in a common directory, then change to the project's directory before running it. All of that project's unit tests will be found and tested, instead of the unit tests in the common directory where regression.py is located.
这个技术允许你在多个项目中重用 regression.py 代码。只需要将这个代码放在一个普通目录中,在运行项目前将路径更改为项目的目录。所有项目的路径将被找到并进行测试工作,而不仅仅局限于 regression.py 所在目录的单元测试。
这个技术允许你在多个项目中重用 regression.py 代码。只需要将这个代码放在一个普通目录中,在运行项目前将路径更改为项目的目录。项目中所有的单元测试被找到并运行,而不仅仅局限于 regression.py 所在目录的单元测试。
16.3 重识列表过滤
本节标题:Filtering lists revisited
过滤已访问列表重识列表过滤
例16.7, (4):你可以通过 for 循环的方式完成相同的工作。根据你编程的背景,……
取决于你的编程背景
例16.8, (2):This is a compiled regular expression.
这时一个复杂的正则表达式。
这是一个预编译的正则表达式。
同上:编译后的对象将含有接受一个被寻找
字符串作为参数的 search 方法。
待寻找
16.4 重识列表映射
本节标题:Mapping lists revisited
关联已访问列表重识列表映射
例16.10, (2):You could accomplish the same thing with a list comprehension. List comprehensions were first introduced in Python 2.0; map has been around forever.
使用列表遍历的方法你可以做到相同的事情。列表遍历是在 Python 2.0 版时被引入的,map 便从此永远盘桓。
列表解析是在 Python 2.0 版时被引入的;而 map 则古老得多。
例16.10, (3):你如果坚持以 Visual Basic 程序员而
自居,通过 for 循环的方法完成相同的任务也完全可以。
例16.12, (1):正如你在 第 4.7 节“使用 lambda 函数” 中所见,lambda 定义一个内嵌函数。也正如你在 例 6.17“分割路径名” 中所见,os.path.splitext 接受一个文件名并返回一个元组 (name, extension)。因此 filenameToModuleName 是一个接受文件名并提出文件扩展名而只返回文件名称的函数。
正如你在 第 4.7 节“使用 lambda 函数” 中所见,lambda 定义一个内联函数。也正如你在 例 6.17“分割路径名” 中所见,os.path.splitext 接受一个文件名并返回一个元组 (name, extension)。因此 filenameToModuleName 是一个接受文件名,剥离出其扩展名,然后只返回文件名称的函数。
例16.12, (2):调用它 map 接受files列出的所有文件名,把它传递给 filenameToModuleName 函数,并且返回每个函数调用结果所组成的列表。
调用 map 将把 files 列出的所有文件名传递给 filenameToModuleName 函数,并且返回每个函数调用结果所组成的列表。
Para -1:如你在本章剩余部分将看到的,你可以将这种数据中心思想扩展应用
到定义和执行一个容纳来自很多单个测试套件的测试的一个测试套件的最终目标。
16.5 数据中心思想编程
Para 2:这就是关键的一步,使你有了被处理
的真实数据:文件名列表。
待处理
Para 3:你有太多数据,因此你需要
过滤( filter )数据。
Para 4:现在你有了每个测试套件的文件名(且局限于测试套件,因为所有其他内容都被过滤掉了),但是你确实
还需要以模块名来替代之。
Para 5:但是 for 循环看起来像是个繁重的工作。至少,简单讲是在浪费时间,糟糕的话还会隐埋错误(
Bug)。比方说,你需要弄清楚如何测试这样一个条件“这个文件是测试套件吗?”不管怎么说,这是应用细化逻辑,没有哪个语言可以让我们这样做。但是一旦你搞清楚了,你还需要费尽周折的定义一个新的空列表、写一个 for 循环以及一个 if 语句并手工地调用 append 将符合条件的元素一个个添加到新列表中,然后一路注意区分那个变量里放着过滤后的数据,那个变量里放着未过滤得老数据吗?
。
例如,你需要弄清楚如何测试这样一个条件:“这个文件是测试套件吗?”这是应用特定的逻辑,没有哪个语言能自动为我们写出其代码。
Para -2:I resisted list comprehensions when I first learned Python, and I resisted filter and map even longer. I insisted on making my life more difficult, sticking to the familiar way of for loops and if statements and step-by-step code-centric programming.
我在第一次学习 Python 时是抵触列表遍历的,而且我抗拒 filter 和 map 的时间更长。我坚持着我更艰难的生活,固守着类似于 for 循环和 if 语句以及一步步地代码编程方式。
我在第一次学习 Python 时是抵触列表解析的,而且我抗拒 filter 和 map 的时间更长。我坚持着我更艰难的生活,固守着类似于 for 循环和 if 语句以及一步步地以代码为中心的编程方式。
Para -1:让这一切都远去吧。费力不讨好的编程不重要,数据重要。并且数据并不难,他们不过就是数据。
并且数据并不麻烦,它们不过就是数据。
16.6 动态导入模块
Para 2:The import module syntax looks in the search path for the named module and imports it by name. You can even import multiple modules at once this way, with a comma-separated list.
import module 语法查看搜索路径寻找已命名模块并以名字导入它们。你甚至于可以以这种方法,以逗号分割同时导入多个模块,本章代码前几行就是这样做的。
import module 语法查看搜索路径,根据给定的名字寻找模块并导入它们。你甚至可以这样做:以逗号分割同时导入多个模块,本章代码前几行就是这样做的。
例16.14, (2):The variable sys is now the sys module, just as if you had said import sys.
变量 sys 现在是 sys 模块,就像你所说的 import sys。
变量 sys 现在是 sys 模块,和 import sys 的结果完全相同。
后面作类似修改。
例16.15上:So __import__ imports a module, but takes a string argument to do it. In this case the module you imported was just a hard-coded string, but it could just as easily be a variable, or the result of a function call.
因此 __import__ 导入一个模块,但是是通过一个字符串参数来做到的。依此处讲,你导入的仅仅是一个硬性的字符串代码,但它可以是一个简单的变量,或者一个函数调用的结果。
因此 __import__ 导入一个模块,但是是通过一个字符串参数来做到的。依此处讲,你用以导入的仅仅是一个硬编码性的字符串,但它可以是一个变量,或者一个函数调用的结果。
例16.15:Importing a list of modules dynamically
动态导入一个列表锁定的模块动态导入模块列表
例16.15, (2):令人惊奇,你需要导入他们,且通过关联 __import__ 到列表实现了。
简单得令人惊奇,通过映射 __import__ 就实现了导入。
Para -1:现在,你应该能够把这一切放在一起
,并能搞清楚本章大部分样例代码的
是做什么的。
16.7 全部放在一起
例16.16下:As you saw in Section 16.2 Finding the path, the script directory will end up in the path variable,...
正如在 第 16.2 节 “找到路径” 中所见,脚本目录将最终存于 path 变量,……
例16.18, (3):剩下的是一个单元测试脚本列表,因为只有它们是
形如 SOMETHINGtest.py 的文件。
例16.19, (2):filenameToModuleName is a function. There's nothing magic about lambda functions as opposed to regular functions that you define with a def statement.
filenameToModuleName 是一个函数。lambda 与你以 def 语句定义的针对正则表达式的函数相比并不神奇。
filenameToModuleName 是一个函数。lambda 函数并不比你以 def 语句定义的普通函数神奇。
例16.20, (2):modules 现在是一个模块列表,像其他模块一样可用。
modules 现在是一个模块列表,其中的模块和其他模块一样。
例16.21:Step 5: Loading the modules into a test suite
步骤 5:将模块调入测试套件
载入
例16.21, (1):这正是 loadTestsFromModule 方法的工作:内省每一个模块并为每个模块返回一个 unittest.TestSuite 对象。每个 TestSuite 对象实际上
都包含了一个 TestSuite 对象列表,每个对象对应着你的模块中的一个测试方法。
例16.21, (2):把 TestSuite 的中文名说明移至第一次出现的地方,例16.21, (1)。
例16.21下:自省过程是 unittest 模块经常为我们做的一项工作。还记得我们的独立测试模块调用并大刀阔斧地完成一起工作的那个看似神奇的 unittest.main() 函数吗?
自省过程是 unittest 模块经常为我们做的一项工作。还记得我们的独立测试模块仅仅调用了看似神奇的 unittest.main() 函数就大刀阔斧地完成了全部工作吗?
例16.22, (1):你已经创建了一个自己就能导入模块、调用 unittest.defaultTestLoader 并封装于一个测试套件的(regressionTest)函数。现在你所要做的不是去寻找测试并以通用的方法构建一个测试套件,而是告诉 unittest 前面那些,它将调用返回可以直接使用的 TestSuite 的 regressionTest 函数。
在不使用 unittest 模块来为我们做这一切的神奇工作的情况下,你实际上已自己做到了。你已经创建了一个自己就能导入模块、调用 unittest.defaultTestLoader 并封装于一个测试套件的 regressionTest 函数。现在你所要做的不是去寻找测试并以通用的方法构建一个测试套件,而是告诉 unittest 前面那些,它将调用 regressionTest 函数,而它会返回可以直接使用的 TestSuite。
16.8 小结
在不使用列表遍历的情况下
,使用 filter 过滤列表。
在不使用列表遍历的情况下,使用 map 关联列表。
不使用列表解析,使用 map 映射列表。