以下是各章修订清单的汇总。
  1. ../2007-06-08

  2. ../2007-06-27

  3. ../2007-06-28

  4. ../2007-07-01

  5. ../2007-07-07

  6. ../2007-07-11

  7. ../2007-07-14

  8. ../2007-07-23

  9. ../2007-07-25

  10. ../2007-07-29

  11. ../2007-08-01

  12. ../2007-08-03

  13. ../2007-08-05

  14. ../2007-08-06

  15. ../2007-08-07

  16. ../2007-08-09

  17. ../2007-08-17

  18. ../2007-08-18

6-8<X1> install.xml 安装 Python

1.1 哪一种 Python 适合您?

  1. Para 2:……大多数Linux发布版本 <!> (./) 发行版

  2. Para -1无论哪一个已经安装再您的计算机上的均可。
    (!) 表达似乎有些别扭,
    (./) 无论哪一个——只要已经安装在您计算机上——均可。

1.2 Windows 上的 Python

  1. Para 2ActiveState 制作了一个 Windows 上的 Python安装程序称为 ActivePython
    (!) 表达很别扭,
    (./) ActiveState 发布 Windows 上的 Python 安装程序,叫做 ActivePython

  2. Para 2附加了 <!> 一些 Windows 扩展 (./) 以及

  3. Para 3曾经 {X} 学习 Python 时

  4. Para 3:新的 Python 版本出来 <!> 几个月 (./) 发布

  5. 过程1.1, 5:……执行一个 {X} 定制安装

  6. 过程1.1, 6Start->Programs
    (!) 能翻译为什么不翻译呢?
    (./) 开始->程序

1.3 Mac OS X 上的 Python

  1. 过程1.4, 2挂装 <!> 到桌面 (./) 挂载

  2. 例1.1上:那您需要知道正在使用 {i} 的是 哪一个版本的 Python。

1.4 Mac OS 9 上的 Python

pass

1.5 RedHat Linux 上的 Python

  1. Para 1:如果你想在像 Linux 一样的 UNIX 兼容的操作系统上……
    (./) 在类 UNIX 的操作系统(如 Linux)上

  2. Para 2:下载最新的 Python RPM {i}

  3. 例1.2, (3):这是我们刚 <!> 的 Python (./) 安装

1.6 Debian GNU/Linux 上的 Python

  1. Para 1:如果您碰巧 {X} 运行在……

1.7 从源代码安装 Python

pass

1.8 使用 Python 的交互 Shell

  1. Para 3:让我们深入下去做这些操作
    (!) 不管原文如何,这里不符合上下文(下文不过是做了1 + 1print 'hello world'这样的简单操作)
    (./) 让我们尝试着做这些操作

6-27<X2> odbchelper.xml 第一个 Python 程序

  1. Para 1: 大家都很清楚,其它书籍是如何…… {i} 还是让我们跳过这个部分吧

2.1 概览

pass

2.2 函数声明

  1. Para 3:Python 不需要提定 <!> 明显typo 返回值的数据类型 (./) 指定

2.2.1 Python 和其他编程语言数据类型的比较

  1. “xx类型定义语言”,这样的表达太罗嗦,按照一般的表达,改为“xx类型语言”
  2. Para 3A language in which types are fixed at compile time
    一种在编译期间数据类型固定的语言
    (!) 明显,原文的被动式在这里应该是表示单纯的被动动作而非状态
    (./) 一种在编译期间就确定数据类型的语言

  3. Para 3Most statically typed languages enforce this by requiring you to declare all variables with their datatypes before using them.
    大多数静态类型语言是通过要求在使用所有变量之前声明它们的数据类型来保证这一点的。
    (!) 很有意思的是,原来的英文读起来很正常,但如实翻译成中文后明显有了逻辑问题。鉴于中英文表达习惯不同,“所有”改为“任一”。相应地,“它们的”改为“其”。
    (./) 大多数静态类型语言是通过要求在使用任一变量之前声明数据类型来保证这一点的。

  4. Para -1:因为只要一个变量具有一个数据类型
    (!) 此处采用更加动态的表达方式似乎更好
    (./) 因为只要一个变量获得了一个数据类型

2.3 文档化函数

  1. Para 1:可以通过给出一个 doc string(文档字符串) {i} 文档化一个 Python 函数

  2. 例2.2下, Para 1, Line -1:但是您可能会发现它们经常定义 doc string 的情况

  3. (!) 怎么就没人嫌别扭呢 (./) 但是您可能会发现它们经常被用于定义 doc string。

2.4 万物皆对象

  1. Para 1如果 <!> 您没在意,我刚才的意思是…… (./) 可能

  2. 例2.3, (1)...a module -- a chunk of code that you can use interactively, or from a larger Python program.
    模块是指……或者来自一个大规模的 Python 程序
    (!) 此处原译太死,不符合中文习惯,语法上也说不过去
    (./) 或者一个大规模的 Python 程序的片段

2.4.1 模块导入的搜索路径

  1. 它会按所有定义在 sys.path 中的目录进行搜索
    (./) 它会按定义在 sys.path 中的目录逐个进行搜索

  2. 例2.4, (2):sys.path 是一个组成 <!> 当前搜索路径的目录列表。 (./) 指定

  3. 例2.4, (3)有一些,像 sys 模块,是……
    (./) 有一些模块(像 sys)

2.5 代码缩进

  1. Para 1:没有花括号,用于标函数的开始和结束
    (!) 改为相对简单的语法结构
    (./) 没有标明函数的开始和结束的花括号

  2. 例2.5, Para 1:代码块 {i} 通过它们的缩进来定义的

  3. 例2.5, Para 1, Line -1:不一定非要是 4 {i} ,只要一致就可以了。没有缩进的第一行则 {i} 被视为 在函数体之外。

  4. 例2.6, (2):包括字符串、整数和其它如字典和列表(我们将在下一章学习)等类型
    (./) 包括字符串、整数和其它类型,如字典和列表(我们将在下一章学习)

  5. 例2.6, (2)通过使用以逗号分割的值列表把几个东西输出到一行上
    (!) 此处表达太罗嗦,且与下文重复了
    (./) 只需用逗号隔开

  6. 例2.6, (3):如果 if 表达式计算为 true,{i} 紧跟着的 缩进块 {i} 被执行

2.6 测试模块

  1. Para 1:您可以使用这些属性方便地测试您所书写 <!> 的模块。 (./) 编写

  2. Para 2:有几 <!> 重要的观察结果 (./)

  3. Para 3:一个模块的 __name__ 的值要看 <!> 您如何应用模块 (./) 取决于

2.-1 反馈

6-28<X3> odbchelper.xml 内置数据类型

3.1 Dictionary 介绍

  1. 例3.2, (2)括号内Yes, this will annoy you someday when you think you are adding new values but are actually just modifying the same value over and over because your key isn't changing the way you think it is.
    是的,它可能某天会给您带来麻烦,您可能以为加入了新值,但实际上只是一次又一次地修改了同一个值,这是因为您的 key 没有按照您的想法进行改变。
    (!) 说实话,不论英文和中文我都花了不少时间才彻底理解Mark是什么意思。翻译得很勉强,我调整了一下语序,添加了一些字词。
    (./) 是的,它可能某天会给您带来麻烦。设想你一次次地修改一个 dictionary,但其间您使用的 key 并未按照您的想法进行改变。您可能以为加入了新值,但实际上只是一次又一次地修改了同一个值。

  2. 例3.4, (2):……可以是字符串、整数 <!> 几种其它的类型 (./)

  3. 例3.4, (2), Line -1:也可以在一个 dictionary 中混用和配匹 明显typo <!> key 的数据类型 (./) 匹配

  4. 进一步阅读, Line -1:……总结了所有 {i} dictionary 方法

3.2 List 介绍

  1. 例3.11, (1), Line -1:并且添加这个 list 中的每个元素到原 list 中 (./) 并且这个 list 中的每个元素添加到原 list 中

  2. 例3.12下, 注解:为了弥补这一点 <!> (./) 这一个缺陷

3.3 Tuple 介绍

  1. 例3.15, (1)A tuple is defined in the same way as a list, except that the whole set of elements is enclosed in parentheses instead of square brackets.
    定义 tuple 与定义 list 的方式相同,除了整个元素集是用小括号包围的而不是方括号。
    (!) 翻译得太死,难道except非要翻译为“除了”吗
    (./) 定义 tuple 与定义 list 的方式相同,整个元素集是用小括号包围的,而不是方括号。

3.4 变量声明

  1. 3.4.1上:幸运的是,与 VBScript 不同的是 {X} ,Python 不允许您引用一个未被赋值的变量,试图这样做会引发一个异常。

  2. 进一步阅读上, Para -1: ……包括os模块, {i} 我们 将在 第 6 章 中讨论

3.5 格式化字符串

  1. 例3.21, (1)The whole expression evaluates to a string.
    整个表达式计算结果为一个字符串。
    (!) 是的,原文中的“evaluates to”的确是“计算结果为”的意思。但明显,中文在此处采用静态意义的表达法更加自然。
    (./) 整个表达式的值为一个字符串。

  2. 同上:在字符串中所有其它的字符
    (./) 字符串中的所有其它字符

  3. 例3.22下, Para 1:不同的格式化格式符和可选的修正符 {i} 用于不同的数据类型

  4. 例3.23, (1):格式符选项被认为是 <!> 一个十进制浮点数 (!) 有点逻辑问题 (./) 映射

3.6 映射 list

  1. 例3.24下, Para 1Here are the list comprehensions in the buildConnectionString function that you declared in Chapter 2:
    声明位于 第 2 章 的函数 buildConnectionString 对 list 的解析:
    (!) 此处翻译得很勉强,不妨罗嗦一点,意思反而更清楚。
    (./) 让我们回过头来看看位于 第 2 章 的函数 buildConnectionString 对 list 的解析:

  2. 例3.25, (1):keys 方法返回一个 {i} 包含 所有键的 list

  3. 例3.25, (2):values 方法返回一个 {i} 包含 所有值的 list

  4. 例3.25, (2):这个 list 以 keys 返回的 list 顺序输出 (./) 它同 keys 方法返回的 list 输出顺序相同

  5. 例3.25, (3):items 方法返回 {i} 一个形如 (key, value) 的 tuple {i} 组成 的 list

  6. 例3.25下, Para 1:这个新 list 将拥有与 params.items 相同的元素数量,在新 list 中的每个元素都将包含从 dictionary.params 来的一个键和与其关联值的字符串
    (!) 翻译得很勉强
    (./) 这个新 list 将与 params.items 一一对应:新 list 中的每个元素都是 dictionary.params 中的一个键-值对构成的的字符串

  7. 进一步阅读:Python Tutorial 展示了如何 {i} 嵌套 list 的 list {i} 进行 解析

3.7 连接 list 与分割字符串

  1. Para 4:总之, {i} 这里的 join 方法将 list 中的元素连接成单个字符串……

  2. Para 4下, 提示:它不进行任何的类型强制转换 <!> (./) 强制类型转换

  3. 进一步阅读上:……在您想要搜索一个子串,然后处理字串前面的东西 <!> (即 list 中第一个元素) 和其后的东西 <!> (即 list 中第二个元素) 时…… (./) 前半部分 后半部分

3.7.1 字符串方法的历史注解

  1. I use the new join method exclusively, but you will see code written either way...
    我只使用新的 join 方法,但是您将会看到代码的其它写法,并且如果它真的使您……
    (./) 我只使用新的 join 方法,但是您还是会看到其它写法。如果它真的使您……

3.8 小结

  1. Line -1:分割字符串 成为 list 和 连接 list 成为字符串
    (./) 把字符串分割为list 和把 list 连接为字符串

3.-1 反馈

7-1<X4> apihelper.xml 自省的威力

  1. Para 1:……Python 中任何东西都是对象 <!> ,…… (!) 为了和前面章节的用词统一, (./) 万物皆对象

4.1 概览

  1. 例4.2上:……它可以使用 <!> 任何……作为参数…… (./) 接受

  2. 例4.2, Para 1:缺省地,程序输出进行了格式化处理 {i} ,以使其易于阅读

4.2 使用可选参数和命名参数

  1. 例4.4下, 提示:调用函数时唯一需要 <!> 做的事情就是为每一个必备参数指定值…… (./) 必须

4.3 使用 type、str、dir 和其它内置函数

  1. Para 1...This was actually a conscious design decision,...
    ……其实这是一个非常明智的设计决策……
    (!) decision固然是“决策”的意思,但我想此处Mark的意思应该是“策略”而不是“决策”。
    (./) ……其实这是一个非常明智的设计策略……

  2. Para 2:添加了脚注:
    这对于处理多种数据类型的帮助者函数 <footnote><para>帮助者函数,原文是 helper function,也就是我们在前文所看到的诸如 <literal>odbchelper</literal>、<literal>apihelper</literal> 这样的函数。——译注</para></footnote> 非常有用。
    (!) helper function这个术语的出现对于英文阅读者十分自然(helper已经出现在函数名中了),但中文版应该予以说明。

4.3.1 type 函数

pass

4.3.2 str 函数

  1. Para 1The str coerces data into a string. Every datatype can be coerced into a string.
    str 将数据强制转型 <!> 为字符串。每种数据类型都可以强制转型为字符串。
    (!) coerce在国内不是通译为“强制转换”吗,我真不知道YuLin是怎么会想到用“转型”这个词的。(台湾译风的影响?)
    (./) 转换

  2. 例4.6, (4)You'll use this to your advantage in the info function...
    你将会使用这一点来提高你的 info 函数
    (./) 你将会使用这一点来改进你的 info 函数

  3. 例4.7, (1):li 是一个列表,所以 dir(li) 返回 {i} 一个包含所有列表方法的一个 {X} 列表。

  4. 例4.8上:如果参数对象是可调用的那么返回 true否则返回 false。
    (./) 如果参数对象是可调用的,返回 true;否则返回 false。

  5. 例4.8, (1)...but the module contains a lot of useful constants like this string.punctuation, which contains all the standard punctuation characters.
    但是在这个模块中包含了许多有用的变量比如 string.punctuation,这个模块包含了所有标准的标点符号字符。
    (!) 估计是一个which把译者给搞懵了,竟然稀里糊涂地翻译成了“模块”
    (./) 但是在这个模块中包含了许多有用的变量,例如 string.punctuation,这个字符串包含了所有标准的标点符号字符。

4.3.3 内置函数

  1. Para 2:像这样考虑的好处是,是你可以获取 __builtin__ 模块信息的…… (!) 估计是typo (./) 你是

  2. Para 2:猜到什么了吗, {i} 现在我们的 Python 有一个称为 info 的函数。 (!) 从上下文来看,info函数明显是作者自己写的,而不是Python原有的。

  3. Para 2, Line -1:……应该看上去已经 {i} 熟悉了。 (!) 这里是为了中文表达的顺畅

4.4 通过getattr获取对象引用

  1. 例4.10, (3):如果不深信它是多么的有用 (./) 确信

  2. 例4.12, (3):现在你可以简单地调用输出函数就像调用其它函数一样
    (./) 现在你可以简单地调用输出函数就像调用其它函数一样。

4.5 过滤列表

  1. Para 3A filter expression can be any expression that evaluates true or false (which in Python can be almost anything)
    过滤器表达式可以是返回值为真或者假(在 Python 中是 几乎任何东西)的任何表达式。
    (!) 又一次没有把握语序,括号里面的内容解说的是expression而非false。况且大多数 Python 表达式的值是真,而不是假。
    (./) 过滤器表达式可以是返回值为真或者假的任何表达式(在 Python 中是 几乎任何东西)

  2. 同上:任何经过滤器表达式演算值为元素的真都可以包含在映射中。
    (./) 任何经过滤器表达式演算值为真的元素都可以包含在映射中。

  3. 进一步阅读上,整段部件 <!> 一律改为更常见的术语, (./) 成员。(不再列出全文,还请自己参看)

  4. 进一步阅读:Python Tutorial 讨论了 使用内置过滤器 <!> 函数……
    (!) 过度翻译,Python里可没有叫做“过滤器”的函数,只有filter函数
    (./) filter

4.6 and 和 or 的特殊性质

  1. 为了和前面章节的用词一致,布尔上下文 <!> 一律改为前文中使用的,也是更好的术语, (./) 布尔环境。顺便说一句,我发现几乎所有被翻译为“上下文”的术语都是指“环境”,不知道 programming 资料的第一批译者是怎么想的

  2. 例4.18上不只 <!> 一次 (./) 不止

  3. 例4.18下:and-or技巧, {i} 也就是bool and a or b表达式……

4.7 使用 lambda 函数

  1. 例4.20, (2)你可以使用 lambda 函数甚至不需要将它赋值给一个变量。
    (./) 使用 lambda 函数甚至不需要将它赋值给一个变量。

  2. 例4.21, (2)split without any arguments splits on whitespace.
    不带参数的 split 按照空格 <!> 进行分割。 (!) 翻译错误 (./) 空白

4.8 全部放在一起

  1. Para 2This is the meat of apihelper.py:
    下面是 apihelper.py 的根本 <!>(./) 关键

  2. Para 4
    Now, let's take it from the end and work backwards. The
    for method in methodList
    现在,让我们从后向前分析。这个
    for method in methodList
    ……
    (!) 从下文看来,这里的“这个”画蛇添足,宁肯去掉。况且“the”翻译为“这个”也不甚妥当。

  3. 例4.23, (1)Confusingly, if you evaluate the __doc__ attribute directly, the Python IDE prints nothing at all, which makes sense if you think about it, but is still unhelpful.
    令人迷惑的是,如果你直接演算 __doc__ 属性的值,Python IDE 什么都不会打印,如果你只是考虑它,是有意义的,但是却没有什么用。
    (!) 翻译有些生硬。if you think about it不译也不会对句子的意思产生多大影响,宁肯不译。
    (./) 这是有意义的,但是却没有什么用。

  4. 例4.25, (1)This is also a useful debugging trick when you're working with lists. And in Python, you're always working with lists.
    在你处理列表时,这确实是一个有用的调试技巧。还有一点在 Python 中,你总是在操纵列表。
    (!) 此处翻译不太灵活,让人费解。
    (./) 在 Python 中,你会十分频繁地操作列表。

4.9 小结

  • pass

4.-1 反馈

7-7<X5> fileinfo.xml 对象和面向对象

5.1 概览

pass

5.2 使用 from module import 导入模块

  1. Para 3:添加了译注,指出文中的错误(和 Mark 联系上后移除)

5.3 类的定义

  1. 例5.4, (1):把原来的译注移到脚注<footnote>里面去了

  2. 例5.4下, 提示:不像在 Java 中有一个特殊的 extends {X} 关键字。

  3. 例5.5:初始化 FileInfo Class (!) 没有翻译?! (./)

  4. 例5.5, (2), Line -1:……但 __init__ 是在 Python 中你可以得到的最接近构造函数的东西,并且它也扮演着非常相同 <!> 的角色。 (./) 相似

  5. 例5.5, (4)__init__ 方法可以接受任意个数的参数,就像函数一样,参数可以用缺省值定义,可以设置成对于调用者可选。
    (./) __init__ 方法可以接受任意数目的参数,就像函数一样,参数可以用缺省值定义,可以设置成对于调用者可选。

  6. 例5.6, (1):Python 不是这样,你必须显示地调用在父类中的适合 <!> 方法。 (./) 合适

5.4 类的实例化

  1. Para 1:……为了对类进行实例化,只要调用类,好像它是一个函数……
    (./) 对类进行实例化,只要调用类(就好像它是一个函数)……

  2. 例5.7, (4):修正一处格式化错误(不再列出)。

  3. 例5.8, (1):然后函数结束 {i} 没有释放 f

5.5 探索 UserDict:一个封装类

  1. Para 1:如你所见,FileInfo 是一个像字典一样动作的类。
    (./) 如你所见,FileInfo 是一个有着像字典一样的行为方式的类。

  2. 例5.9, (5), Line -1:你可以用这种语法,或者可以在后面的行拥有缩近代码…… (./) 写下

  3. 例5.9下, Para 1:一个类可以有同名的多个方法,但这些方法或者是参数个数不同, <!> 参数的类型不同。 (!) 为保持一致, (./) 或者是

  4. 例5.9下, Para 2Guido, the original author of Python, explains method overriding this way: "Derived classes may override methods of their base classes. Because methods have no special privileges when calling other methods of the same object, a method of a base class that calls another method defined in the same base class, may in fact end up calling a method of a derived class that overrides it. (For C++ programmers: all methods in Python are effectively virtual.)" If that doesn't make sense to you (it confuses the hell out of me), feel free to ignore it. I just thought I'd pass it along.
    Python 的原作者 Guido 是这样解释方法覆盖的 “子类可以覆盖父类中的方法。因为方法没有特殊的优先级设置,在调用同一对象的另外方法时,父类中一个方法对另一个同类中的方法的调用,可能其实调用到的却是一个子类中覆盖父类同名方法的方法。(对于 C++ 程序员,所有的 Python 方法都非常有效)” 如果你不明白(它另我颇感困惑),不必在意。我想我要跳过它。
    (!) 明显这位兄台没有理解 Guido 的话,也不懂 C++。
    (./) Python 的原作者 Guido 是这样解释方法覆盖的:“子类可以覆盖父类中的方法。因为方法没有特殊的优先级设置,父类中的一个方法在调用同类中的另一方法时,可能其实调用到的却是一个子类中覆盖父类同名方法的方法。(C++ 程序员可能会这样想:所有的 Python 方法都是虚函数。)”如果你不明白(它另我颇感困惑),不必在意。我想我要跳过它。
    (./) 同时添加了一段译注,帮助读者理解。

  5. 例5.10, (1), Line -1在你忘记的情况下 <!> ,字典的 clear 方法删除它的所有关键字和关键字相应的值。 (./) 你可能已经忘了

  6. 例5.10, (3):我们使用 __class__ 属性来查看是否 self 是 <!> 一个 UserDict…… (./) self 是否是

  7. 例5.10, (4), Line -1是否你想到要自已研究它了呢? (./) 你是否已经

  8. 例5.10下, Para 1UserDict出色于模仿字典。 (./) UserDict能十分出色地模仿字典。

5.6 专用类方法

  1. Para 1:除了普通的类方法,还有一些对于 Python 类可以定义的专用方法。
    (./) 除了普通的类方法,对于 Python 类还有一些可以定义的专用方法。

  2. 例5.14上, Para -1, Line -1:它还要在文件自身内进行搜索 MP3 的标记然后填充一整套关键字集合 {X} 。下面的例子将展示其如何工作(./) 工作方式

  3. 例5.14, (1):注意我们的 __setitem__ 方法严格按照 父类方法相同的形式进行定义。

  4. 例5.14, (4):注意,我们在调用直接父类,FileInfo,尽管它没有一个 {X} __setitem__ 方法。没问题,因为 Python 将会沿着父类树走,直到它找到一个有着 <!> 我们正在调用方法的类,…… (./) 拥有

  5. 例5.15, (2):关键字触发了 MP3FileInfo 上的 __setitem__ 方法( 不是 UserDict

5.7 高级专用类方法

  1. 例5.16下, 注解:关于 Java 的技术评注翻译了两次。合并为一次。

  2. 注解下, Para 2:任何类可以表现得像一个序列,只要通过 {X} 定义 __getitem__ 方法。

  3. 同上:并且如果你的类表现 拥有类似长度的东西……

  4. 进一步阅读上:允许你在类实例上进行加,减, <!> 执行其它算数操作。 (./) 以及

5.8 类属性介绍

  1. 例5.17, (2):它 {X} 在创建任何类实例之前就有效了。

  2. 例5.17下:在 Java 中,静态变量和实例变量两者 {i} 是紧跟在类定义之后定义的……

  3. 同上:到后面 <!> ,它只会把你(或其它人)搞乱。 (./) 最后

5.9 私有函数

pass

5.10 小结

  1. 子类化 UserDict 来定义作为 <!> 像字典的类 (./) 行为

5.-1 反馈

7-11<X6> fileinfo.xml 异常和文件处理

本章的修订参考了某人放在项目主页上的反馈。请看到此页后在此加上自己的名字,谢谢!

6.1 异常处理

  1. 列举下:在这些情况下,我们都在简单使用 Python IDE:一个错误发生了,异常被打印出来(根据你的 IDE,有意地以一种刺眼的红色形式表示)
    (./) 在这些情况下,我们都在简单使用 Python IDE:一个错误发生了,异常被打印出来 (取决于你的 IDE,可能会有意地以一种刺眼的红色形式表示)

  2. 下一段:但是许多时候,一个异常是可以预计 <!> 的…… (./) 预见

  3. 例 6.1 下, Para 1Would you rather get back an unusable file object to a non-existent file?
    希望获得一个没有用的文件对象而不是一个不存在的文件吧?
    (!) 注意这里的to,不是表比较,而是引导object的定语,表指向(这样的用法很常见,eg. a pointer to an integer)
    (./)该不会希望获得一个指向不存在的文件的对象吧

  4. 例6.2, (1):termios 是一个 UNIX 特定模块
    (./) termios 是一个特定的 UNIX 模块

  5. 例6.2, (2):……它是一个 Windows 特定模块
    (./) 它是一个特定的 Windows 模块

  6. 例6.2, (3):它是一个 Mac OS 特定模块
    (./) 它是一个特定的 Mac OS 模块

  7. 例6.2, (4):……注意我们在这里做的:…… (./) 注意我们在这里做的:……

  8. 例6.2, (5):一处样式错误。还请参见源文件。

  9. 例6.2, (5), Line -1
    Each of the other try...except blocks has similar else clauses to bind getpass to the appropriate function when you find an import that works.
    其它每个 try...except 块有着相似的 else 子句,当我们找到一个 import 可用时,来绑定 getpass 到适合的函数。
    (./) 其它每个 try...except 块有着相似的 else 子句,当我们发现一个 import 可用时,绑定 getpass 到适合的函数。

6.2 与文件对象共事

  1. 作名词短语的打开文件 <!> 一律改为 (./) 被打开文件

6.2.1 读取文件

  1. Para 1:……正如下一个例子所显示 <!> 的。 (./) 展示

  2. 例6.4, (2):0 表示移动到一个绝对位置(从文件开始算起),0 表示移到一个相对位置(从当前位置算起),还有 2 表示对于文件尾的一个相对位置。
    0 表示移动到一个绝对位置(从文件起始处算起),1 表示移到一个相对位置(从当前位置算起),还有 2 表示相对于文件尾的位置。

  3. 同上:添加了译注,说明了“文件尾”指的是文件的结束标记,而不是最后一个字节。

  4. 例6.4, (3):tell 方法确认了已经移到当前文件位置
    (!) 有必要和 例6.4, (5) 里面的用词保持一致(原文可是一致的)。
    (./) tell 方法确认了当前位置已经移动了

  5. 例6.4, (4):我们本可以在这里简单地说一下 {X} read(),……

6.2.2 关闭文件

  1. Para 1:打开文件消耗系统资源,并且依赖于文件模式,其它程序或许不能访问它们
    (./) 打开文件消耗系统资源,并且其间其它程序可能无法访问它们(取决于文件模式)

  2. 例6.5, (1):……打开文件要消耗系统资源,并且根据文件模式,其它程序可能不能使用它们。……
    %^$#`?!!原文可没有把上文重复一次啊
    (./) 删去!

  3. 例6.5, (2):刷新被缓冲的系统确实 {X} 还未写入的输出(如果有的话),……

  4. 例6.5, (4)只是因为文件被关闭,并不意味着文件对象停止存在。
    (./) 文件被关闭但这并不意味着文件对象不再存在。

6.2.3 处理 I/O 错误

  1. 例6.6, (5):一旦文件通过 open 函数被成功地打开,我们应该绝对保证把它关闭,甚至由于 seek 或 read 方法引发了一个异常。
    (./) ……即使是在 seek 或 read 方法引发了一个异常

  2. 例6.6, (6), Line -1:……并且处理将正常继续,从 tryexcept 块的下一行代码 {i} 开始

6.2.4 写入文件

  1. Para 2, 3:"Append" 模式将数据追加到文件尾。
    "write" 模式将覆盖文件的原有内容。
    (!) 有必要交代一下中文含义。
    (./) 追加(Append)模式将数据追加到文件尾。
    写入(write)模式将覆盖文件的原有内容。

  2. 例6.7, (1):你可以大胆地开始创建任何的 {X} 新文件 test.log 或覆盖现有文件,……

  3. 例6.7, (3):file 是 open 的同义语。它用一行打开文件,读取内容,并打印它们。
    (./) ……这一行语句打开文件,读取内容,并打印它们。

  4. 例6.7, (5):……同时注意回车符并没包含进来
    (!) 意思不是很清晰
    (./) 同时注意两行之间并没包含回车符

6.3 for 循环

  1. 例6.8, (2):for 循环可以在它里面有任意条数的代码行。
    (!) 前者不符合中文表达习惯;“条数”和“代码行”有重复之嫌。
    (./) for 循环可以包含任意数目的代码行。

  2. 例6.8, (3):这就是为什么你以前没看到过 for 循环的原因:…… (!) 与后面的“原因”重复了。 (./) 删去

  3. 例6.10, (3):使用 多变量赋值 和 list 解析,你可以使用单行语句来替换整个 for 循环。在实际的编码中是否这样做只是个人风格问题;我喜欢它是因为,可以使得 {X} 将一个 dictionary 映射到一个 list,然后将 list 合并成一个字符串,这一过程显得很清晰。

  4. 例6.11, (1)一旦我们读出文件最后 128 个字节,第 3 到 32 字节总是歌曲的名字,……
    (./) 只要我们读出文件最后 128 个字节,那么第 3 到 32 字节总是歌曲的名字,……

  5. 例6.11, (2)这个 <!> for 变量结构…… (./) 这里的

  6. 例6.11, (3):……,接着将 parseFunc {i} 的返回值 作为值赋值给伪字典 self 中的键字 tag。
    (!) 根据上下文来看,这里指的是返回值。

6.4 使用 sys.modules

  1. 例6.12, (1)这个 {X} sys 模块包含了系统级的信息,……

  2. 例6.14, (1):每个 python 类 {i} 拥有一个内置的 类属性 __module__,……

  3. 例6.15, (3):hasattr 是一个补充性的函数,用来检查是否一个对象具有一个特别的属性;……
    (./) 用来检查一个对象是否具有一个特定的属性……

6.5 与 Directory 共事

  1. 例6.16, (2):ospath 的 join 函数一个或多个部分路径名构造成一个路径名。
    (./) ospath 的 join 函数一个或多个部分路径名连接成一个路径名。

  2. 例6.16, (3):当 {X} 发现这一点时我高兴极了,……

  3. 例6.16, (5):将这些技术 <!> 在一起,…… (./) 组合

  4. 例6.18, (1):listdir 函数接收一个路径名,返回那个目录的内容的一个 list。
    (./) listdir 函数接收一个路径名,返回那个目录的内容的 list。

  5. 例6.18, (3):在这里,我们使用 ospath.join 来确保一个全路径名,但 isfile 对一个相对于当前工作目录的部分路径也是有效的。你可以使用 os.getcwd() 来得到当前的工作目录
    (./) 在这里,我们使用 ospath.join 来确保得到一个全路径名,但 isfile 对部分路径(相对于当前目录)也是有效的。你可以使用 os.getcwd() 来得到当前目录

  6. 例6.19, (4):我们查看是否扩展名在我们关心的文件扩展名 list 中……
    (./) 我们查看扩展名是否在我们关心的文件扩展名 list 中……

  7. 例6.19下, 提示:只要有可能,你应该使用在 os 和 ospath 中的函数进行文件目录和路径的操作。
    (./) 只要有可能,你应该使用在 os 和 ospath 中的函数进行文件、目录和路径的操作。

  8. 例6.20上:还有一种获得 directory <!> 内容的方法。 (./) 目录

  9. 例6.20, 标题Listing Directories with glob (./) 使用 glob 列出目录

  10. 例6.20, (1):正如你前面看到的,os.listdir 简单地取出一个目录路径,目录中的所有文件和子目录。
    (./) 正如你前面看到的,os.listdir 简单地一个目录路径,返回目录中的所有文件和子目录。

  11. 例6.20, (2):glob 模块,另一方面,选取 <!> 一个通配符…… (./) 接受

  12. 例6.20, (4)你可以用两个通配符仅仅调用 glob 一次立刻获得所有这些文件的一个 list。
    (./) 使用两个通配符仅仅调用 glob 一次就可以立刻获得所有这些文件的一个 list。

6.6 全部放在一起

  1. 例6.21, (1):listdirectory 是整个模块主要的引吸 <!> 之处。 (./) 有趣

  2. 例6.21, (2):……这行代码得到一个全路径名的列表,它们 <!> 是在 directory 中…… (./) 它的元素

  3. 例6.21, (6):接着我们创建这个类(不管它是什么)的一个实例,传入文件名(又是 f)给 {X} init 方法。

  4. Para -1:请注意 listdirectory 完全是通用的。它事先不知道将得到文件哪种类型或者哪些定义好的类能够处理这些文件。
    (./) ……它事先不知道将得到哪种类型的文件也不知道哪些定义好的类能够处理这些文件。

6.7 小结

  1. Para -1动态地 实例化未知类型的类 通过将类看成对象并传入参数
    (./) 通过将类看成对象并传入参数,动态地 实例化未知类型的类

6.-1 反馈

7-14<X7> re.xml 正则表达式

re.xml 中不知为何不少 XML tag 和 entity 都被破坏了,都逐一修复了~~
本章 typo 太多,故均不列出。
  1. Para 1:……它们的语法非常相似,那么你仅仅阅读一下 re 模块的摘要,大致了解其中可用的函数和参数就可以了。
    (./) 由于它们的语法非常相似,你仅仅阅读一下 re 模块的摘要,大致了解其中可用的函数和参数就可以了。

7.1 概览

  1. Para 2If what you're trying to do can be accomplished with string functions, you should use them. They're fast and simple and easy to read, and there's a lot to be said for fast, simple, readable code.
    如果你要解决的问题利用字符串函数能够完成,你应该使用它们。它们快速、简单且容易阅读,而对于快速、简单、可读性强的代码等方面有很多内容
    (./) ……它们快速、简单且容易阅读,而快速、简单、可读性强的代码可以说出很多好处

7.2 个案研究:街道地址

  1. 例7.1下, Para 1很快,我发现上面的例子,仅仅匹配地址末尾的……
    (./) 很快我发现,在上面的例子中,……

  2. 例7.2, (1):你利用 \b,……在 python 中,由于字符'\'在一个字符串中必须转义这个事实,从而变得非常麻烦。
    (./) 由于字符 '\' 在一个字符串中必须转义,这会变得非常麻烦。

7.3 个案研究:罗马字母

  1. 确定了几个术语的使用:“fives character”翻译为“含五字符”(原译“被5整除的字符”),同样地,“tens character”翻译为“含十字符”(原译“被10整除的字符”)。原译注删去。
  2. Para 1:这是一个表示数字的系统,它能够真正回溯到远古的罗马帝国(因此而得名)。 (./) 它实际上能够追溯到远古的罗马帝国

  3. 列举, 最后一条:罗马数字经常 <!> 从高位到低位书写,…… (./) 一般

7.3.1 校验千位数

  1. Para 1:……由于罗马数字经常 <!> 是从高位到低位书写,…… (./) 一般

  2. 例7.3, (1)^表示仅仅 <!> 在一个字符串的开始匹配其后的字符串内容。 (./)

  3. 同上:M?可选地匹配单个字符 M,由于它 {i} 重复出现三次,…… (!) 根据上文 (./) 最多

  4. 例7.3, (2):re 模块的本质是一个 search 函数
    (!) 模块的本质是函数??
    (./) 模块的关键是一个 search 函数

  5. 同上:你此刻关注的唯一事情,就是模式是否匹配上,可以利用 search 函数的返回值弄清这个事实。
    (./) ……于是我们利用 search 函数的返回值了解这个事实。

  6. 例7.3, (3):'MM' {i} 匹配上是因为…… (./)

  7. 例7.3, (4):'MMM' {i} 匹配上是因为…… (./)

  8. 例7.3, (5):'MMMM' 没有匹配上。因为所有的三个 M 都匹配上,但是正则表达式还有字符串尾部的限制(由于字符 $),然而字符串没有结束……
    (./) 'MMMM' 没有匹配上。因为所有的三个 M 都匹配完了,但是正则表达式还有字符串尾部的限制(由于字符 $),字符串又没有结束

7.3.2 检验百位数

  1. 标题检验百位数 (!) 为和上一节标题“校验千位数”一致, (./) 校验百位数

  2. 文中多次出现了X位数位置 <!> ,实际上指的就是 (./) X位数,一律修正。

  3. Para 1:……,具体用那种方式表达和具体的数值相关
    (./) 具体用那种方式表达和具体的数值有关

  4. 第二次列举:零到三次出现 C 字符(如果是零,表示百位数为 0(./) 出现零次表示百位数为 0

  5. 例7.4, (2):因此 CD 和 D?C?C?C? 两个模式甚至 {X} 不再考虑

  6. Para -1吆!来看正则表达式能够多快变得难以理解?
    (!) 这个语气叹词我可没见过(字典里也找不到这一义项,只能解释为动词,不能做语气词)。
    (./) 哎呀!来看正则表达式能够多快变得难以理解?

7.4 使用 {n,m} 语法

  1. Para 1:在 前面的章节,你处理了相同字符可以重复三次的情况,在正则表达式中有另外一个方式来表达这种情况,并且使代码的可读性更好
    (./) 在前面的章节,你处理了相同字符可以重复三次的情况在正则表达式中有另外一个方式来表达这种情况,并且能提高代码的可读性

  2. 例7.6, (1)The 0 and 3 can be any numbers; if you want to match at least one but no more than three M characters, you could say M{1,3}.
    可是是 0 到 3 之间的任何数字,如果你想要匹配至少 1 次,至多 3 次字符 M,则可以写成 M{1,3}。
    (./) 这里的 0 和 3 可以改成其它任何数字;如果你想要匹配至少 1 次,至多 3 次字符 M,则可以写成 M{1,3}。
    (!) 对照原文,不难判定孰正孰误。

  3. 例7.6, (5):但是 没有匹配 <!> 字符串的结尾。 (!) 根据上文,这里应当是 (./) 没有匹配上

  4. 例7.6下, 注解:没有一个轻松的方法来确定两个正则表达式是否为等价的,……在本书后面的章节,关于如何书写测试样例有更多的讨论
    (./) 没有一个轻松的方法来确定两个正则表达式是否等价。……在本书后面的章节,将更多地讨论如何编写测试样例

7.4.1 校验十位数和个位数

  1. Para 1:现在我们来扩展扩展关于罗马数字的正则表达式,……
    (./) 现在我们来扩展一下关于罗马数字的正则表达式,……

  2. 7.4 Para -2:……我曾经做过这样的事情,但是它并不是那么好看 <!>(./) 有趣

7.5 松散正则表达式

  1. 例7.9, (1):当使用松散正则表达式时,请记住 {X} 最重要的一件事情就是:……

7.6 个案研究:解析电话号码

  1. 例7.10, (1)通常是从左到右阅读正则表达式,……
    (./) 我们通常从左到右阅读正则表达式

  2. 为了用词的统一,后文的分割符 <!> 一律改为 (./) 分隔符

  3. 例7.14, (1):这个正则表达式和前面的几乎相同,除了在第一个记忆组(区号)前面匹配……
    (./) 这个正则表达式和前面的几乎相同,但它在第一个记忆组(区号)前面匹配……

  4. 例7.14, (4):但是你认为在区号前面的所有字符都是非数字字符(\D*)。Aargh.
    (!) 没有翻译??!!
    (./) ……唉!

  5. 例7.15, (2):……,不论这个电话号码的首字符是数字还是不是数字还是在电话号码不同部分之间加上任意数目的任意类型的分隔符。,……
    (./) ……,无论这个电话号码的首字符是不是数字无论在电话号码各部分之间有多少任意类型的分隔符。

7.7 小结

  1. x? 匹配一个可选的 x 字符(换句话说,它匹配 1 次或者 0 次 x 字符)。 (./) 换言之

  2. Para -1:一些人,当遇到一个问题时,想“……”
    (./) 一些人,遇到一个问题时就想:“……”

7.-1 反馈

7-23<X8>dialect.xml HTML 处理

  • 感谢 zhangfance。

    本章频繁 typo:显示显式混用。

8.1 概览

  1. Para 1How do I parse/translate/munge the text of my HTML document but leave the tags alone?
    怎么才能 [分析|解释|munge] 我的 HTML 文档的文本,但是不要标记呢
    (!) “leave alone”的意思是“不惊动,不涉及”,而非“不要”。
    (./) 怎么才能 [分析|解释|munge] 我的 HTML 文档的文本,但是又要保留标记呢

8.2 sgmllib.py 介绍

  1. Para 5:开始标记(Start tag)是一个 {X} 开始一个块的 HTML 标记,像……

  2. 警示, Line -1在这 <!> 错误在 python 2.1 中改正了。 (./) 这个

8.3 从 HTML 文档中提取数据

  1. Para 2If you have some HTML lying around on your hard drive, you can use file functions to read it,... 如果在您的硬盘里存放着 HTML 文件,您可以使用 file 函数 将它读出来,……
    (!) 就链接的指向来看,file functions 指的是 (./) 处理文件的函数

  2. 例8.6, (1), Line -1:……当某人重用一个分析器实例时, <!> 正确地重新初始化 (./) 可以

  3. 例8.6, (3):我们可以通过一个简单的 多变量 list 映射来查找是否这个 <a> 标记拥有一个 href 属性。
    (./) 我们可以通过一个简单的 多变量 list 映射来查找这个 <a> 标记是否拥有一个 href 属性。

  4. 例8.7, (1), 脚注:……也许因为这就选择了 feed 这个名字。 (!) 汉语博大精深的词汇怎么不好好利用啊 (./) 因此

  5. 整节 Line -1{i} 如果 当您读到此处发现输出结果不一样,那是因为下载了本书的更新版本。

8.4 BaseHTMLProcessor.py 介绍

  1. Para 1:您可以通过将 SGMLParser 子类化来定义一个类,……
    (./) 您可以定义 SGMLParser 的子类,……

  2. Para 2SGMLParser 子类化 BaseHTMLProcessor (./) BaseHTMLProcessor 子类化 SGMLParser

8.5 locals 和 globals

  1. ……一会 {i} 我们就会看到

  2. 例8.10上, Para 1, Line 1:您是否为此而感到困惑?不要绝望(!) 汗……哪这么容易绝望
    (./) 您是否为此而感到困惑?不要灰心

  3. 例8.10下, Para 1不仅仅是模块的名字空间包含了模块级的变量和常量,它还包括了所有在模块中定义的函数和类。再加上,它包括了任何被导入到模块中的东西。
    (./) 模块的名字空间不仅仅包含了模块级的变量和常量,包括了所有在模块中定义的函数和类。除此以外,它包括了任何被导入到模块中的东西。

  4. 下一段:这就是为什么您可以直接访问它们却不需要引用它们所来源的模块的原因 {X}
    (!) 原句明显病句(句式杂糅)。

  5. 例8.11, 样例输出:原文最后的“rest of output omitted for brevity”翻译为“略”是正确的。但是这段输出是放在<programlisting>里面的,在语法着色的时候会把中文分解成XML标记,显示出来也是XML标记而不是中文。改回“rest of output omitted for brevity”。

  6. 例8.11, 样例输出, (1)SGMLParser 使用了 from module import 从 sgmllib 中被导入。
    (!) 中文的表达采用主动式更自然。
    (./) 我们使用了 from module import SGMLParser 从 sgmllib 中导入。

  7. 例8.11, 样例输出, (2):对比这个和 htmlentitydefs,它是用 import 被导入的。也就是说 htmlentitydefs 模块本身也在名字空间中,但是 entitydefs 变量定义在 htmlentitydefs 之外。
    (!) 上下文无法全部列出,还请参看原文。
    (./) 把上面的例子和 htmlentitydefs 对比一下,它是用 import 被导入的。也就是说 htmlentitydefs 模块本身被导入了名字空间,但是定义在 htmlentitydefs 之中的 entitydefs 变量却没有

  8. 例8.11, 样例输出, (4):当运行一个模块时 ( <!> 从另外一个模块中导入而言) (./) 相对于

  9. 例8.12上, Line -1It will bite you anyway, but at least then you'll remember learning it.
    它无论如何都会困扰您的,但至少您还记得了解过它。
    (./) 它无论如何都会困扰您的,但至少您还会记得曾经学习过它。

  10. 例8.12, (1):locals 是一个返回 dictionary 的函数,并且 {i} 在 dictionary 中设置 {i} 一个值。

8.6 基于 dictionary 的字符串格式化

  1. 例8.13, (1):这个名字是 params dictionary 中的一个键字,并且将 %(pwd)s 标记所在的地方替换成相应的值 secret。
    (./) 所以 %(pwd)s 标记所在的地方替换成相应的值 secret。

  2. 例8.13, (3)You can even specify the same key twice; each occurrence will be replaced with the same value.
    您甚至可以两次指定同一键字,每个键字发生之处将被同一个值所替换。
    (./) 您甚至可以两次指定同一键字,每个键字出现之处将被同一个值所替换。

  3. 例8.14上Well, it does seem like overkill to set up a dictionary of keys and values simply to do string formatting in the next line;
    好,在下面一行中,仅为了进行字符串格式化就需要创建一个有键字和值的 dictionary 看上去的确有些小题大作。
    (./) 的确,仅为了进行字符串格式化,就事先创建一个有键字和值的 dictionary 看上去的确有些小题大作。
    (!) 看看原文就不难知道孰正孰误。“下一行”这个意思没有保留。原文的next line也只是笼统的概念,不一定创建了这样一个 dictionary 后就非得在下一行进行字符串格式化。

  4. 例8.15, (1), b:在这个列表理解 <!> 的第一轮循环中,…… (./) 解析

  5. 例8.15, (1), c:这个字符串就作为这个列表理解 <!> 返回值的第一个元素。 (./) 解析

8.7 给属性值加引号

  1. Para 2:即使它们可能以大写字母开始或是大小写的混和 <!> 形式。 (./) 混合 (!) 连我自己起初都不相信,但这确实是错别字。

  2. 例8.16, 标题:Quoting attribute values (!) 又一次没有翻译 (./) 给属性值加引号

8.8 dialect.py 介绍

  1. 例8.17, (1)每次 SGMLParser 在 HTML 源代码中…… (!) 此处的“每次”改为 (./) 每当。后面相似的句型作一样的修改,不再列出。

  2. 例8.17, (2):我们可以将它作为一个标志,并且把它设为 1 或重置为 0,但这样做……
    (./) 我们本可以把它实现为一个标志,即或把它设为 1,重置为 0,

  3. 例8.18, (1)The only thing left to do is figure out whether there is a specific handler method for this tag, or whether you should fall back on the default method.
    唯一要做的事情就是找到对于这个标记是否存在一个特别的处理方法,或者是否我们应该求助于缺省方法。
    (./) 唯一要做的事情就是检查对于这个标记是否存在一个特别的处理方法,否则我们应该求助于缺省方法。

  4. 例8.18, (2):您以前可能还没注意到的是 getattr 将查找定义在一个对象的继承者中或对象自身的方法。
    (./) 您以前可能还没注意到 getattr 将查找定义在一个对象的继承者中或对象自身的方法。

  5. 例8.18, (4):正如您看一 <!> 的,…… (!) typo (./) 看到

  6. 例8.18, (5):……来调用 getattr 实败 <!> 了。 (./) 失败

  7. 例8.18, (8)start_xxx and do_xxx methods are not called directly; the tag, method, and attributes are passed to this function, handle_starttag, so that descendants can override it and change the way all start tags are dispatched. You don't need that level of control, so you just let this method do its thing, which is to call the method (start_xxx or do_xxx) with the list of attributes.
    start_xxx 和 do_xxx 方法并不被直接调用标记名、方法和属性被传给 handle_starttag 这个方法,以便继承者可以覆盖它,并改变 全部 开始标记分发的方式。我们不需要控制层,所以我们只让这个方法做它自已的事,就是用属性属性 {X} 的 list 来调用方法 (start_xxx 或 do_xxx) 。
    (!) that level of controlcontrol而非level是中心语 (./) start_xxx 和 do_xxx 方法并不被直接调用标记名、方法和属性被传给 handle_starttag 这个方法,以便继承者可以覆盖它,并改变 全部 开始标记分发的方式。我们不需要控制这个层面上,所以……

  8. 例8.19上:当我们跑题时,我们正在定义 <!> 特别的处理方法来处理…… (./) 定义了

8.9 全部放在一起

  1. Para 1:到了 {X} 将迄今为止我们已经学过并用得不错的东西放在一起的时候了。

  2. 例8.20, (3)Now you get the source of the given URL.
    现在我们得到了给定的URL的原始资料了(./) 现在我们得到了给定的 URL 源文件了

  3. 例8.21, (1)Combined with some string formatting, you've taken the name of a dialect and transformed it into the name of the corresponding Dialectizer class.
    与某个字符串格式化合在一起使用后,我们就得到了一种方言的名字,接着将它转化为相应的方言变换器类的名字。
    (./) 再使用字符串格式化,我们就得到了一种方言的名字,将它转化为相应的方言变换器类的名字。

  4. 例8.21, (2):我们有了一个字符串形式 (parserName) 的类名称,还有一个 dictionary (globals()) 形式的全局名字空间。合起来后,我们可以得到一个以前面字符串 <!> 命名的类的引用。 (./) 前者

  5. 例8.21, (3):……像函数一样调用类。这个类保存在一个局部变量中的事实完全不会有什么影响;……
    (./) 这个类保存在一个局部变量中,但这个事实完全不会有什么影响

  6. 例8.21下, Para 1Why bother?
    怎么这么麻烦?
    (./) 何必这么麻烦?

  7. 例8.22, (1)After all that imagining, this is going to seem pretty boring, but the feed function is what does the entire transformation.
    毕竟那只是假设,这个似乎会非常令人讨厌,但这个 feed 函数执行了全部的转换工作。
    (./) 剩下的工作似乎会非常无聊,但实际上,feed 函数执行了全部的转换工作。

  8. 进一步阅读:您可能会认为我正在拿服务端脚本编程开玩笑。在我发现这个 基于 web 的方言转换器 之前,的确是这样认为的。
    (./) 您可能会认为我的服务端脚本编程的想法是开玩笑。在我发现这个 基于 web 的方言转换器 之前,的确是这样的。

8.10 小结

  1. 汇集结果,如 URL lister (!) 根据 URL lister 的实际用途,改为 (./) 摘录结果

  2. 按结构的方式对其进行修改,如 属性引用
    (./) 在处理过程中顺便调整结构,如 给属性值加引号

8.-1 反馈

7-25<X9>kpg.xml XML 处理

  • 为了术语的一致,把file-like object 统一译为“类文件对象”。

9.1 概览

  1. Para 1:下面两章是关于 Python 中 XML 处理的。如果你已经知道一个 XML 文档的样子,……
    (./) 如果你已经对 XML 文档有了一个大概的了解

  2. Para 3:Being a philosophy major is not required, although if you have ever had the misfortune of being subjected to the writings of Immanuel Kant, you will appreciate the example program a lot more than if you majored in something useful, like computer science. (!) 又一次没有翻译
    (./) 如果你在大学里主修哲学(而不是像计算机科学这样的实用专业),并且曾不幸地被伊曼努尔·康德的著作折磨地够呛,那么你会非常欣赏本章的样例程序。(这当然不意味着你必须修过哲学。)

  3. 例9.3, 标题:Sample output of kgp.py (./) kgp.py 的样例输出

  4. 例9.3下, Para 1, Line -1:但所有内容都 {X} 符合康德的风格。

  5. 例9.4上The interesting thing about this program is that there is nothing Kant-specific about it. 关于这个程序的有趣之处在于没有一点内容是属于康德的。
    (./) 有趣之处在于,这个程序中没有一点内容是属于康德的。

9.2 包

  1. 例9.5, (1):这个语法你之前没有见过。它看上去很像我们所知并且喜欢的 from module import,但是……
    (./) 这个语法你之前没有见过。它看上去很像我们熟知的 from module import,但是……

  2. 例9.6下Python 认为它的意思是:“在 xml 目录中查找 dom 目录,然后在中查找 minidom 模块,……”
    (!) 原文即为斜体
    (./) 在 xml 目录中查找 dom 目录,然后在 这个目录 中查找 minidom 模块

  3. 例9.7, (1):……为了能够引用 minidom 模块中的类(比如 Element),你必须在它们的类名前面加上模块名。
    (./) 引用 minidom 模块中的类(比如 Element),你必须在它们的类名前面加上模块名。

  4. 例9.7, (3)Here you are importing the dom package (a nested package of xml) as a module in and of itself.
    这里你正在导入 dom 包(xml 的一个嵌套包),并将其作为自己或者内部的 {X} 一个模块。
    (!) in and of 只是对itself 的强调

9.3 XML 解析

  1. 例9.8, (1):正如在上一 {X} 节看到的,……

  2. 例9.8, (2):它只是我本地磁盘上一个 XML 文档的文件名。(为了继续执行, {X} 你需要将路径改为指向下载的例子所在的目录。)

  3. 例9.12, 标题:Drilling down all the way to text (./) 把文本挖出来

  4. 例9.12, (2)The ref element has its own set of child nodes, one for the carriage return, a separate one for the spaces, one for the p element, and so forth.
    ref元素有它自己的子节点集合,一个表示硬回车,一个独立表示空格的,一个用于p元素的,诸如此类。
    (./) ref 元素有它自己的子节点集合,一个表示硬回车,一个表示空格,一个表示 p 元素,诸如此类。

  5. 例9.12, (3):你甚至可以在这里使用 toxml 方法, {i} 尽管它深深嵌套在文档中。

  6. 例9.12, (3):p 元素只有一个子节点(在这个例子中,你无法知道这一点,……)
    (./) p 元素只有一个子节点(在这个例子中无法看出……)

9.4 Unicode

  1. 历史注解, Para 1:……在系统之间进行文档交流是困难的,因为对于一台计算机来说,没有方法可以识别出文档的作者使用了哪种编码模式;计算机看到的只是数字,并且这些数字可以表示不同的东西。接着考虑到试图将这些 {i} (采用不同编码的)文档存放到同一个地方(比如在同一个数据库表中);……比较有代表性的是使用转义符来进行模式切换; <!> ,我们处于俄语 koi8-r 模式,所以字符 241 表示这个;,现在我们处于 Mac 希腊语模式,…… (./)
    (!) 原文太长,不能全部列出。

  2. 历史注解, Para 3, Line -1:Unicode使用同7位 ASCII 码一样的字符表示0到127同ISO-8859-1一样的字符表示128到255,接着使用剩余的数字,256到65535,扩展到表示其它语言的字符。
    (./) Unicode 在 0 到 127 上使用了同 7 位 ASCII 码一样的字符表在 128 到 255上同 ISO-8859-1 一样,接着使用剩余的数字,256 到 65535,扩展到表示其它语言的字符。

  3. 历史注解, Para 4:……或将数据打印输出到一个非unicode识别终端或打印机。
    (./) 或将数据打印输出到一个不识别 unicode 的终端或打印机。

  4. 例9.13上, Para -1:从2.0版本开始,Python 在整个语言的基础上已经支持unicode。
    (./) 从 2.0 开始,Python 整个语言都已经支持 unicode。

  5. 例9.14, (2):还记得我说过 print 函数会尝试将unicode字符串转换为 ASCII,这样就可以打印它了吗?
    (./) 还记得我说过 print 函数会尝试将 unicode 字符串转换为 ASCII 从而打印它吗?

  6. 例9.14, (3):……我们使用 latin-1(也就是大家知道的 iso-8859-1)
    (./) 我们使用 latin-1(也叫 iso-8859-1)

  7. 例9.15, (2):Python 会在任何需要自动将unicode字符串强制转换为正规字符串的地方,使用这个编码模式。
    (./) Python 会在任何需要将 unicode 字符串自动转换为正规字符串的地方,使用这个编码模式。

  8. 例9.15, (1)The default encoding can only be changed during Python startup; you can't change it later. (Due to some wacky programming tricks that I won't get into right now, you can't even call sys.setdefaultencoding after Python has started up.
    默认的编码只会在 Python 启动的时候改变;之后就不能改变了。(由于一些古怪的编程技巧,我没有马上深入,你甚至不能在 Python 启动之后调用sys.setdefaultencoding函数。……)
    (./) 由于一些我们现在不会仔细研究的古怪的编程技巧,你甚至不能在 Python 启动之后调用 sys.setdefaultencoding 函数。

  9. 例9.18上:现在,想想 XML 中的编码应该是怎样的呢?不错的是 {X} ,每一个 XML 文档都有指定的编码。

  10. 例9.19, (3):打印title是不可能的,因为这个unicode字符串包哈了非 ASCII 字符,……
    (./) 直接打印 title 是不可能的,因为这个 unicode 字符串包含了非 ASCII 字符,……

  11. 例9.19, (4)你能够,但是,显式将它转换为koi8-r,……
    (./) 但是,你能够显式将它转换为 koi8-r,……

  12. 进一步阅读:PEP 263 涉及了何时、如何在你的 .py 文件中定义字符 {i} 编码的更多细节。

9.5 搜索元素

  1. Para 1:在这部分,将使用 binary.xml 语法文件,它看上去是这样的
    (./) 在这部分,将使用 binary.xml 语法文件,它的内容如下

  2. 例9.20上:它有两个 ref,'bit' {i} (位)和 'byte' {i} (字节)

  3. 例9.22, (3):在本例中,你有两个,每“位”使用一个。
    (./) 在本例中,你有两个元素,每“位”各占一个。
    (!) 还请参见原文

9.6 访问元素属性

  1. Para 3:这部分由于某个涵义 <!> 重叠的术语可能让人有点糊涂。 (./) 含义 (!) 这不是错别字,但属于非推荐词形1

  2. 例9.24, (1):每个 Element 对象都有一个称为 attributes {X} 属性

  3. 例9.24, (5):……那些非常认真的读者将已经知道 NamedNodeMap 类是如何实现这一技巧的:通过定义一个 __getitem__ 特殊方法
    (!) 为和前面的术语一致,改为 (./) 专用方法

  4. 同上{i} 它的读者可能乐意接受这一事实:……

  5. 例9.25, (1):与你在 bitref.attributes NamedNodeMap {X} 伪目录中寻找的对象同名

9.7 Segue

  1. 标题:有必要解释一下标题的含义。加入了脚注:
    “Segue”是音乐术语,意为“继续演奏”。

  2. Para 1OK,that's it for the hard-core XML stuff. (!) 又一次……
    (./) 以上就是 XML 的核心内容。

9.-1 反馈

7-29<X10>kpg.xml 脚本和流

  1. “接收……作为参数”一律改为“接受……作为参数”
  2. 本章标题Scrips 和 Streams (./) 脚本和流

10.1 抽象输入源

  1. Para 1:Python 的最强大力量之一是它的动态绑定,并且动态绑定最强大的用法之一是类文件(file-like)对象。
    (./) Python 的最强大力量之一是它的动态绑定,动态绑定最强大的用法之一是类文件(file-like)对象。

  2. 例10.1上, Para -2:只要你将一个类文件对象传递给函数,函数只是调用对象的 read 方法,函数可以处理任何类型的输入源,而不需要处理每种类型的特定代码
    (./) 只要你将一个类文件对象传递给函数,函数只是调用对象的 read 方法,就可以处理任何类型的输入源,而不需要为处理每种类型分别编码

  3. 例10.1上, Para -1:你可能纳闷这和 XML 处理有什么关系,…… (./) 你可能纳闷……

  4. 例10.1, (3):确保处理完 {X} 文件后调用 close 方法。

  5. 例10.2上:哦,所有这些看上去象是在浪费大量的时间。毕竟,你已经看过 minidom.parse 可以只接收文件名,并自动执行所有打开文件和关闭无用文件的行为。不错,如果你知道正要解析的是一个本地文件,你可以传递文件名而且 minidom.parse 可以足够聪明的做正确的事情™,这一切都不会有问题。但是请注意,使用类文件分析直接从Internet上来的 XML 文档是多么相似和容易的事情
    (./) 哦,所有这些看上去像是在浪费大量的时间。毕竟,你已经看到,minidom.parse 可以只接收文件名,并自动执行所有打开文件和关闭无用文件的行为。不错,如果你知道正要解析的是一个本地文件,你可以传递文件名而且 minidom.parse 可以足够聪明地做正确的事情(Do The Right Thing™),这一切都不会有问题。但是请注意,使用类文件,会使分析直接从 Internet 上来的 XML 文档变得多么相似和容易
    (!) 我就纳闷了,怎么“做正确的事情”也成了 trademark。顺便加了个注释 {i} 这是一部著名的电影。——译注

  6. 例10.2, (1){i} 前一章中所看到的,……

  7. 例10.2, (4)By the way, this URL is real, and it really is XML. It's an XML representation of the current headlines on Slashdot, a technical news and gossip site.
    顺便提一句,这个 URL 是真实的,它真的是一个 XML。它是Slashdot站点(这是一个技术新闻和随笔站点)上当前标题的 XML 表示。
    (./) 顺便提一句,这个 URL 是真实的,它真的是一个 XML。它是 Slashdot 站点(一个技术新闻和随笔站点)上当前新闻提要的 XML 表示。

  8. 例10.3下OK,所以你可以使用 minidom.parse 函数来解析本地文件和远端 URL,但对于解析字符串,你使用……一个不同的函数。
    (./) 好吧,所以你可以使用 minidom.parse 函数来解析本地文件和远端 URL,但对于解析字符串,你使用……另一个函数。

  9. 例10.4上:如果有一个方法可以把字符串转换成类文件对象,那么你可以只把 <!> 这个对象传递给 minidom.parse 就可以了。 (./) 只要

  10. 例10.4, (1):StringIO 模块只包含了单个 <!> 类,也叫 StringIO,它允许你将一个字符串转换为一个类文件对象。这个 {X} StringIO 类在创建实例的时候接收字符串作为参数。 (./) 一个

  11. 例10.4, (4):任何时候,read 都将返回字符串的未读剩余 {X} 部分。

  12. 例10.5, (1):……它将调用对象的 read 方法并高兴的开始解析,绝不会知道它的输入源 {X} 自一个硬编码的字符串。

  13. 例10.5下:那么现在你知道了如何使用单个 <!> 函数,minidom.parse,来解析一个保存在 web 页面上、本地文件中或硬编码字符串中的 XML 文档。 (./) 同一个

  14. 例10.6, (1):……source 是某种类型的字符串;它可能是一个 URL(例如 'http://slashdot.org/slashdot.rdf' ),一个本地文件的完整或者部分路径名(例如 'binary.xml'),或者是一个包含了需要解析 <!> XML 数据的字符串。待解析

  15. 例10.6, (2)This is actually elegant in the sense that, if urllib ever supports new types of URLs in the future, you will also support them without recoding.
    这里通过强制方式进行:尝试把它当作一个 URL 打开并静静地忽略打开非 URL 引起的错误。感觉上 {X} 这样做非常好,因为如果 urllib 将来支持更多的 URL 类型,不用重新编码就可以支持它们。

  16. 例10.6, (3):再一次,你不用做任何特别的事来检查 source 是否是一个有效的文件名(总之在不同的平台上,判断文件名有效性的规则变化很大,那么不管怎样做都可能会判断错)。
    (./) 再一次,你不用做任何特别的事来检查 source 是否是一个有效的文件名(在不同的平台上,判断文件名有效性的规则变化很大,因此不管怎样做都可能会判断错)。

  17. 例10.6, (4):到这里,你需要假设 source 是一个其中有硬编码数据的字符串(因为没有什么可以判断的了),所以你可以使用 StringIO 从中创建一个类文件对象并将它返回。(实际上,由于使用了 str 函数,所以 source 没有必要一定是字符串;它可以是任何对象,你可以使用它的字符串表示形式,通过它的定义的 __str__ 特殊方法。) (./) 到这里,你需要假设 source 是一个其中有硬编码数据的字符串(因为没有别的可以判断的了),所以你可以使用 StringIO 从中创建一个类文件对象并将它返回。(实际上,由于使用了 str 函数,所以 source 没有必要一定是字符串;它可以是任何对象,你可以使用它的字符串表示形式,只要定义了它的 __str__ 专用方法。)

  18. 例10.6下:……构造一个函数,接收一个指向 XML 文档的 source,而且无需知道这个 source 的含义, <!> 解析它。 (./) 然后

10.2 标准输入、输出和错误

  1. Para 2:……当你 print 某些东西时,结果前往 stdout 管道;当你的程序崩溃并打印出调试信息(类似于 <!> Python 中的 {i} traceback(错误跟踪))的时候,信息前往 stderr 管道。 (./) 例如

  2. 例10.8, (1):正如 {i} 例 6.9, “简单计数”中看到的,……

  3. 例10.8, (3)像 stdout <!> ,stderr 并不为你添加硬回车;如果需要,要自己加上。 (./) 和 stdout 一样

  4. 例10.8下:……然而,它们仍然是类文件对象,并且你可以将其它任何文件或者类文件对象赋值给它们来重定向它们的输出。
    (./) 然而,它们仍然是类文件对象,因此你可以将其它任何(类)文件对象赋值给它们来重定向其输出。

  5. 例10.9:在 Windows 上,你可以使用 type 来代替 cat 显示文件的内容。
    (./) 在 Windows 上,你使用 type 来代替 cat 显示文件的内容。

  6. 例10.9, (4)所有后续的输出重定向到刚才打开的新文件上。
    (./) 所有后续的输出都会被重定向到刚才打开的新文件上。

  7. 例10.9, (5):这样只会将输出结果“printed <!> ”到日志文件中;…… (./) 打印

  8. 例10.10上:重定向 stderr 以完全相同的方式进行,用 sys.stderr 代替 sys.stdout。
    (./) 重定向 stderr 以完全相同的方式进行,只要把 sys.stdout 改为 sys.stderr

  9. 例10.10, (4)Also note that you're not explicitly closing your log file, nor are you setting stderr back to its original value. This is fine, since once the program crashes (because of the exception), Python will clean up and close the file for us, and it doesn't make any difference that stderr is never restored, since, as I mentioned, the program crashes and Python ends. Restoring the original is more important for stdout, if you expect to go do other stuff within the same script afterwards.
    还要注意你既没有显式关闭日志文件,也没有将 stderr 设回最初的值。这样挺好,因为一旦程序崩溃(由于引发的异常),Python 将替我们清理并关闭文件,这和永远不恢复 stderr 不会造成什么不同,因为,我提到过,一旦程序崩溃,则 Python 结束如果你希望在同一个脚本的后面去做其它的事情,恢复初始值对 stdout 更为重要。
    (./) 还要注意你既没有显式关闭日志文件,也没有将 stderr 设回最初的值。这样挺好,因为一旦程序崩溃(由于引发的异常),Python 将替我们清理并关闭文件,因此永远不恢复 stderr 不会造成什么影响。然而对于 stdout,恢复初始值相对更为重要——你可能会在后面再次操作标准输出(!) 原文比较长,所以 Mark 反复强调了程序崩溃后 Python 的行为。译文相对简洁,就没有这个必要了。

  10. 例10.11上:向标准错误写入错误信息是很常见的,所以有一种较快的语法可以立刻信息导出 <!>(./) 导出信息

  11. 例10.11, (1)This shorthand syntax of the print statement can be used to write to any open file, or file-like object. In this case, you can redirect a single print statement to stderr without affecting subsequent print statements. print 语句的快捷语法可以用于向任何打开的文件写入,或者是类文件对象在这种情况下,你可以将单个 print 语句重定向到 stderr 而且不用影响后面的 print 语句。
    (./) print 语句的快捷语法可以用于写入任何打开的文件(或者是类文件对象)在这里,你可以将单个 print 语句重定向到 stderr 而且不用影响后面的 print 语句。 (!) in this case 指上文的那一行语句。

  12. 例10.11下:标准输出,另一方面,只是一个只读文件对象,它表示从前一个程序到这个程序的数据流。这个对于老的 Mac OS 用户和 Windows 用户可能不太容易理解,除非你受到过 MS-DOS 命令行的影响。它工作的方式是你可以在单个命令行中构造一个命令的链,……
    (./) 另一方面,标准输入是一个只读文件对象,它表示从前一个程序到这个程序的数据流。这个对于老的 Mac OS 用户和 Windows 用户可能不太容易理解,除非你受到过 MS-DOS 命令行的影响。在 MS-DOS 命令行中,你可以使用一行指令构造一个命令的链,……

  13. 例10.12, (3):该处打印 binary.xml 的内容,但是“|”字符,称为“管道”符,说明内容不会打印到屏幕上。而且,它们会成为下一个命令的标准输入,在这个例子中是你调用的 Python 脚本。 (./) 该处打印 binary.xml 的内容,但是“|”字符,称为“管道”符,说明内容不会打印到屏幕上它们会成为下一个命令的标准输入,在这个例子中是你调用的 Python 脚本。

  14. 例10.12, (4):但是想想这里的扩展性。代替cat binary.xml,你可以通过运行一个脚本动态生成语法,然后你可以通过管道将它导入你的脚本。它可以来源于任何地方:数据库,或者是生成语法的元脚本,或者其他。你根本不需要修改你的 kgp.py 脚本就可以混合使用这个功能。
    (./) 但是想想这里的扩展性。让我们把 cat binary.xml 换成别的什么东西——例如运行一个脚本动态生成语法——然后通过管道将它导入你的脚本。它可以来源于任何地方:数据库,或者是生成语法的元脚本,或者其他。你根本不需要修改你的 kgp.py 脚本就可以并入这个功能。

  15. 例10.13, (1):……所有你要做的就是在函数的开始加入 3 行代码来检测源是否是“-”;如果是,返回 sys.stdin。实际上,that's it! <!> (./) 就这么简单!

10.3 查询缓冲节点

  1. 本节标题缓冲节点查询 (./) 查询缓冲节点

  2. Para 1:kgp.py 使用了多种技巧,对你进行 XML 处理而言它们或许有用。第一个就是,使用输入文档的结构稳定特征来构建节点缓冲。
    (./) kgp.py 使用了多种技巧,在你进行 XML 处理时,它们或许能派上用场。第一个就是,利用输入文档的结构稳定特征来构建节点缓冲。

  3. Para 2:……每个 ref 包含了一个或者多个 p 元素,p 元素可以包含很多不同的东西,包括 xref。无论何时你遇到一个 xref,都可以通过相同的 id 属性找到相对应的 ref 元素,并选择 ref 元素的子元素之一进行解析。
    (./) ……每个 ref 包含了一个或多个 p 元素,p 元素则可以包含很多不同的东西,包括 xref。对于每个 xref,你都能找到相对应的 ref 元素(它们具有相同的 id 属性),然后选择 ref 元素的子元素之一进行解析。

  4. Para 3如何构建语法:为最小的片段定义 ref 元素,然后通过 xref 定义“包含”第一个 ref 元素的 ref 元素,等等。然后,解析“最大的”引用并跟在每个 xref 后面,最后输出真实的文本。
    (./) 语法的构建方式如下为最小的片段定义 ref 元素,然后使用 xref 定义“包含”第一个 ref 元素的 ref 元素,等等。然后,解析“最大的”引用并跟着 xref 跳来跳去,最后输出真实的文本。

  5. 例10.14, (2):……返回所有特定名称元素的一个列表。你可以很容易地得到所有 ref 元素的一个列表,然后仅仅是 {X} 遍历这个列表。

10.4 查找节点的直接子节点

  1. 例10.16, (2)However,…… (./) 然而,……

  2. 例10.16, (3):每个节点都有一个 nodeType 属性,它可以是元素节点, 文本节点, 注释节点,或者任意数量的其它值。可能值的完整列表在xml.dom包的 init.py 文件中。(关于包更多的,参见9.2节, “包”。)但你只是对元素节点有兴趣,所以你可以过滤出一个列表,其中只包含 nodeType 是元素节点的节点。
    (./) 每个节点都有一个 nodeType 属性,它可以是ELEMENT_NODE, TEXT_NODE, COMMENT_NODE,或者其它值。可能值的完整列表在 xml.dom 包的 init.py 文件中。(关于包的介绍,参见9.2节, “包”。)但你只是对元素节点有兴趣,所以你可以过滤出一个列表,其中只包含 nodeType 是ELEMENT_NODE的节点。

  3. 例10.16, (4):……将会是 p 元素的一个列表,并且 chosen 将以被赋予其中的一个确切值而结束,而这个值是随即选择的。
    (./) ……将会是 p 元素的一个列表, chosen 将被赋予其中的某一个值,而这个值是随机选择的。

10.5 根据节点类型创建不同的处理器

  1. 本节标题通过节点类型创建独立的处理句柄 Creating separate handlers by node type (./) 根据节点类型创建不同的处理器

  2. Para 1:Document还包含了一个或者多个Element对象(for actual XML tags),其中的每一个可以包含其它的Element对象,Text对象(for bits of text),或者Comment对象(for embedded comments)。
    (./) Document 还包含了一个多个 Element 对象(表示 XML 标记),其中的每一个可以包含其它的 Element 对象、Text 对象(表示文本),或者 Comment 对象(表示内嵌注释)

  3. 例10.17下:好,现在你能够得到任何特定 <!> XML 节点的类名了…… (./) 给定

  4. 例10.18:parse, 一个通用 {X} XML 节点分发器

  5. 例10.18, (1)First off, <!> 注意…… (./) 首先,……

  6. 例10.19, (1):……它只是turn around并解析语法文件的根元素。
    (./) 它只是起到中转作用,转而解析语法文件的根元素。

  7. 例10.19, (4):parse_Element方法其实本身就是一个分发器,它基于元素的标记名称。……对其它的标记名称在解析语法文件的时候都可以找到类似的函数(<p>标记,<choice>标记)
    (./) parse_Element 方法其实本身就是一个分发器,一个基于元素的标记名称的分发器。……对其它的标记名称(像<p> 和 <choice>)在解析语法文件的时候都可以找到类似的函数

10.6 处理命令行参数

  1. 为了术语的一致,本节的“标志”改为“标记”。
  2. Para 1:Python 完备支持创建在命令行运行的程序,并且连同命令行参数和短长样式来指定各种选项。
    (./) Python 完全支持创建在命令行运行的程序,也支持通过命令行参数和短长样式来指定各种选项。

  3. 例10.20, (1):每个传递给程序的命令行参数都在sys.argv,它仅仅是一个列表。
    (./) 每个传递给程序的命令行参数都在 sys.argv 它仅仅是一个列表。

  4. 例10.21, (4):标记自身和标记参数只是sys.argv列表中的序列元素。 (./) 标记自身和标记参数只是 sys.argv 列表中的一串元素。

  5. 例10.21下:但是,but then again, it doesn't look like it's going to be all that easy to actually use it.
    (./) 但是接下来要实际使用它似乎不那么容易。

  6. 例10.22, (1)First off,…… (./) 首先

  7. 例10.22下, 例10.23上:原稿对参数的解释未译。已译。

  8. 短参解释下, Para 1:你选择是否指定它们,它们做某些事情(打印帮助)或者改变状态(关闭调试 <!>(./) 打开调试

  9. 同上:……实际上,它可以是一个文件名或者一个 web 地址,你可能还不知道(后面你会明白的)……
    (./) 实际上,它可以是一个文件名或者一个 web 地址,这时还不知道(后面会确定)

  10. 短参解释down, Para 2To further complicate things,…… (./) 更复杂的是

  11. 长参解释下这里要注意的三件事:
    (./) 这里有三点要注意:

  12. 长参解释下, 3.:这也好;只有-d才会打开调试。
    (./)很好;只有 -d 才会打开调试。

  13. 例10.23, (4)记得,-d标记没有相应的长标志,……
    (./) 别忘了,-d 标志没有相应的长标志

  14. 例10.23, (5):如果你找到了一个语法文件,-g标志或者--grammar标志带着的,那你要保存跟在它(保存在arg)后面的参数到变量grammar中,覆盖掉在main函数你初始化的默认值。
    (./) 如果你找到了一个语法文件,跟在 -g 或者 --grammar 标志后面,那你就要把跟在后面的参数(arg)保存到变量grammar 中,覆盖掉在 main 函数你初始化的默认值。

  15. 例10.23, (6):That’s it。……并且source将以空字符串结束。
    (./) 就是这样。……而 source 将是空字符串。

10.7 全部放在一起

  1. Para 3:……然后将语法文件和源文件传给它…… (./) 然后将语法文件和源文件传给它

  2. Para 5:……这些引用 {i} 只是 XML 文档中的元素

  3. Para 6:……否则你将打开语法 {i} 文件查找……

  4. Para -5You bounce through the grammar, parsing all the children of each p element,
    通过语法的反弹,解析所有 p 元素的孩子,
    (./) 你在语法里面跳来跳去,解析每一个 p 元素的所有孩子,

  5. Para -2Eventually, you parse your way down to plain text,
    最后,你以你的方式进行解析直到普通文本。 (./) 就这样一直解析,最后得到普通文本。

  6. Para -1:你打印出来的。
    (./) 把结果打印出来。

10.8 小结

  1. Para 1:Python 带有解析和操作 XML 文档非常强大的库。这个 {X} minidom 接收一个 XML 文件并将其解析为 Python 对象,……

8-1<X11>openanything.xml HTTP web 服务

  • 频繁typo:
    • 意谓 (./) 意味

    • hander 多处被误认为header,因此被翻译成了“头信息”,改为处理器

  • 类似文件的对象一律改为类文件对象

  • client 一律译为客户端

  • file-like object 一律译为类文件对象

11.1 概览

  1. Para 2Simply stated, HTTP web services are programmatic ways of sending and receiving data from remote servers using the operations of HTTP directly.
    简单地讲,HTTP web 服务是指直接使用 HTTP 操作从远程服务器按部就班地发送和接收数据。
    (./) 简单地讲,HTTP web 服务是指以编程的方式直接使用 HTTP 操作从远程服务器发送和接收数据。

  2. Para 3The main advantage of this approach is simplicity,...
    利用这种方法的要点简单的,……
    (./) 这种方法的主要优点是简单,……

  3. 例11.1上, Para -2:在后面的几章里,我们将探索使用 HTTP <!> 数据发送和接收传输的 API…… (./) 进行

11.2 避免通过 HTTP 重复地获取数据

  • pass

11.3 HTTP 特性

  1. 重定向, Para 3:……然后在 Location: 头部给出新地址
    (./) 然后在 Location: 头信息中给出新地址

  2. Last-Modified/If-Modified-Since, Para 1
    通常服务器指导 <!> 你所请求的数据的最后修改时间 (./) 知道

  3. Last-Modified/If-Modified-Since, Para 2
    ……你可以告诉服务器你上一次获得的最后修改日期:在你的请求中发送 {X} 一个 If-Modified-Since 头信息……为什么 {X} 这一点有何进步呢?因为 {X} 当服务器发送状态编码 304 时,不再重新发送数据……

  4. Last-Modified/If-Modified-Since, Para 4
    所有现代的浏览器都支持最近修改 {i} (last-modified)的数据检查。……服务器简单地返回 304: {i} Not Modified( 没有修改

  5. ETag/If-None-Match, Para 1
    ETag 是实现与最近修改数据检查同样的功能的另一种方法:没有变化时不重新下载数据。其工作原理 方式是:服务器发送你所请求的数据的同时,发送某种数据的 hash (在 ETag 头信息中 {i} 给出),hash 的确定完全取决于服务器。当第二次请求相同的数据时, {i} 你需要在 If-None-Match: 头信息中包含 ETag hash,……在第二次请求时,通过包含 ETag hash,你 {X} 告诉服务器……

  6. 压缩, Para 1When you talk about HTTP web services, you're almost always talking about moving XML back and forth over the wire. XML is text, and quite verbose text at that, and text generally compresses well.
    当谈论 HTTP web 服务时,几乎总是会谈及在网络线路上传输的 XML。XML 是文本,而且还是相当冗长的文本,并且文本通常可以被很好地压缩。
    (./) 关于 HTTP web 服务的主题几乎总是会涉及在网络线路上传输的 XML。XML 是文本,而且还是相当冗长的文本,文本通常可以被很好地压缩。

11.4 调试 HTTP web 服务

  1. 例11.3, (1)...you can set the debugging flag on the HTTPConnection class that urllib uses internally to connect to the HTTP server. 你可以为 urllib 使用内部的 HTTPConnection 类设置调试标记来访问 HTTP 服务器
    (./) 你可以为 HTTPConnection 类(urllib 在内部使用它来访问 HTTP 服务器)设置调试标记

  2. 例11.3, (6):服务器也会告诉你响应请求的数据、一些有关服务器自身的信息, {i} 以及传给你的数据的内容类型。

11.5 设置 User-Agent

  1. 例11.4, (1):如果你的 Python IDE 仍旧为上一节的例子而打开着,你可以略过这一步,在开启 HTTP 调试 <!> 你能看到网络线路上的实际传输过程。 (./)

  2. 例11.4, (3):第二步是创建一个 URL 开启器 (opener)。可以使用任何数量的操作者来控制响应的处理。但你也可以创建一个没有任何自定义处理的开启器,这就是这里的操作方式
    (./) 第二步是创建一个 URL 开启器 (opener)。可以接受任何数量的处理器来控制响应的处理。但你也可以创建一个没有任何自定义处理器的开启器,在这儿你就是这么做的

  3. 例11.5 Request 添加头信息 (./) Request 添加头信息

  4. 例11.5, (2)Convention dictates that a User-Agent should be in this specific format: an application name, followed by a slash, followed by a version number.
    User-Agent 的协商指令应该使用如下的特殊格式:应用名,跟一个斜线,跟版本号。
    (./) User-Agent 的约定格式是:应用名,跟一个斜线,跟版本号。

  5. 同上User-Agent 通常要记录经过服务器的连同你的请求的其他详细信息,包含你的应用的 URL,如果发生错误,允许服务器管理员通过查看他们的访问日志与你联系。
    (./) 和你的请求的其他信息一样,User-Agent 会被服务器纪录下来,其中包含你的应用的 URL。如果发生错误,服务器管理员就能通过查看他们的访问日志与你联系。

  6. 例11.5, (3):之前你创建的 opener 对象也可以再生,且它将再次获得相同的 feed,但是使用了你自定义的 User-Agent 头信息。
    (./) 但这次使用了你自定义的 User-Agent; 头信息。

  7. 例11.5, (4):若你继续看,会注意到你定义的 User-Agent 头信息,你实际上发送了一个 User-agent 头信息。看看有何不同?urllib2 改变了大小写所以只有首字母是大写的。这没问题,因为 HTTP 规定头子段名完全是大小写无关的。
    (./) 若你继续看,会注意到你定义的 User-Agent 头信息,但实际上发送的是 User-agent 头信息。看看有何不同?urllib2 改变了大小写所以只有首字母是大写的。这没问题,因为 HTTP 规定头信息的字段名是大小写无关的。

11.6 处理 Last-Modified 和 ETag

  1. 作名词短语的调用程序一律改为主调程序

  2. Para 1:接下来看看 {i} 如何添加 Last-Modified 和 ETag 头信息的支持。

  3. 例11.6, (1):这里便是你如何以编程方式访问它们
    (./) 这里便是用编程方式访问它们的方法

  4. 例11.6, (3)You can see from the traceback that urllib2 throws a special exception, HTTPError, in response to the 304 status code.
    毫无疑问,数据没被改变。你可以从跟踪返回结果看到 urllib2 扔掉了特殊异常,HTTPError,响应中的 304 状态代码。
    (./) 毫无疑问,数据没被改变。你可以从跟踪返回结果看到 urllib2 抛出了一个特殊异常,HTTPError,以响应 304 状态代码。

  5. 例11.7上:urllib2 也为你认为是错误的其他条件引发 HTTPError 异常,……当你企图捕获状态代码并简单返回它,不抛弃任何异常时,这应该对你很有帮助。
    (./) urllib2 也为你认为是错误的其他条件引发 HTTPError 异常,……捕获状态代码并简单返回它,而不是抛出异常,这应该对你很有帮助。

  6. 例11.7, (1): 当某事件发生——比如一个 HTTP 错误,以至一个 304 代码——urllib2 审视用于处理它的 一系列已定义的处理器方法。你使用了一个与 第 9 章 XML 处理 类似的自省为不同节点类型定义了一些处理器,……
    (./) 当某事件发生时——比如一个 HTTP 错误,甚至是 304 代码——urllib2 审视用于处理它的 一系列已定义的处理器方法。在此要用到自省,与 第 9 章 XML 处理 中为不同节点类型定义不同处理器类似

  7. 例11.7, (2):当从服务器遇到 <!> 一个 304 状态代码,…… (./) 接收到

  8. 例11.8, (2):还记得我怎么说 urllib2 将一个 HTTP 资源的访问过程分解为三个步骤的正当理由吗?这便是为什么构建 HTTP 开启器就是它自身的步骤,……
    (./) 这便是为什么构建 HTTP 开启器是其步骤之一

  9. 例11.8, (3)Now you can quietly open the resource, and what you get back is an object that, along with the usual headers (use seconddatastream.headers.dict to acess them), also contains the HTTP status code. In this case, as you expected, the status is 304, meaning this data hasn't changed since the last time you asked for it.
    现在你可以快速地打开一个资源,返回给你的是,连同常规头信息在内的对象 (使用 seconddatastream.headers.dict 访问它们),也包括 HTTP 状态代码。在这种情况下,向你所期望的,状态代码是 304,意味着此数据自从上次请求后没有被修改。
    (./) 现在你可以快速地打开一个资源,返回给你的对象既包括常规头信息 (使用 seconddatastream.headers.dict 访问它们),也包括 HTTP 状态代码。在此,正如你所期望的,状态代码是 304,意味着此数据自从上次请求后没有被修改。

  10. 例11.8, (4):注意当服务器返回 304 状态代码时,并没有重新发送数据。这就是全部的关键:没有重新下载未修改的数据 {i} ,从而节省了带宽。

  11. 例11.8下:处理 ETag 的工作也非常相像,不是检查 Last-Modified 并发送 If-Modified-Since,而是检查 ETag 并发送 If-None-Match。
    (./) 处理 ETag 的工作也非常相似,只不过不是检查……

  12. 例11.9Supporting ETag/If-None-Match (./) 支持 ETag/If-None-Match

  13. 例11.9, (1):如果服务器没有返回 ETag 会发生什么?那么这一行将返回 None。
    (./) 答案是,这一行代码将返回 None。

  14. 例11.9, (5):无论 304 是否是被 Last-Modified 数据检查或 ETag hash 匹配触发的,你从来都不会连同数据一起获得 304
    (./) 无论 304 是被 Last-Modified 数据检查还是 ETag hash 匹配触发的,获得 304 的同时都不会下载数据

11.7 处理重定向

  1. 例11.10, (1)You'll be better able to see what's happening if you turn on debugging. 你最好看看开启调试状态时发生了什么。
    (./) 你最好开启调试状态,看看发生了什么。

  2. 例11.11上This is suboptimal, but easy to fix. urllib2 doesn't behave exactly as you want it to when it encounters a 301 or 302, so let's override its behavior. 这不太理想,但很容易改进。实际上当 urllib2 遇到 301 或 302 时并不做行为,所以让我们来覆盖这些行为。
    (./) 这不太理想,但很容易改进。实际上当 urllib2 遇到 301 或 302 时的行为并不是我们所期望的,所以让我们来覆盖这些行为。

  3. 例11.11, (1):重定向行为定义在 urllib2 的一个叫做 HTTPRedirectHandler 的类中。我们不想完全地覆盖这些行为,只想做点扩展,所以我们 {X} 子类化 HTTPRedirectHandler,从而我们仍然可以调用祖先类来实现所有原来的功能。

  4. 例11.11下:这将为我们带来什么?现在你可以构造一个用自定义重定向处理器的 URL 开启器,并且它依然能自动跟踪重定向,并且现在也能展示出重定向状态代码。
    (./) 这将为我们带来什么?现在你可以用自定义重定向处理器构造一个的 URL 开启器,并且它依然能自动跟踪重定向,也能展示出重定向状态代码。

  5. 例11.12, (3)The next time you request this data, you should request it from the new location (..., as specified in f.url)
    下一次你请求这个数据时,就应该在 f.url) 指定使用新地址……
    (./) 下一次你请求这个数据时,就应该使用 f.url 指定的新地址

  6. 例11.13, (1):这是一个 URL 的例子,我已经设置了它,配置它告知客户端为一个到 ... 的临时重定向
    (./) 这是一个 URL,我已经设置了它,让它告诉客户端临时重定向到...。

  7. 例11.13, (2):服务器返回 302 状态代码,标识出 {X} 一个临时重定向。

11.8 处理压缩数据

  1. 本节标题:处理压缩 {X} 数据

  2. 多处file 未译。

  3. 例11.15, (2)OK, this step is a little bit of messy workaround. python has a gzip module, which reads (and actually writes) gzip-compressed files on disk. ... So what you're going to do is create a file-like object out of the in-memory data (compresseddata), using the StringIO module.
    OK,只是先得有点儿凌乱的步骤。python 有 gzip 模块,它读取 (并实际写入) 磁盘上的 gzip 压缩文件。……那么怎么做来创建一个内存数据 (compresseddata) 之外的类文件对象呢,需要使用 StringIO 模块。
    (./) 好吧,只是先得有点儿凌乱的步骤。python 有一个 gzip 模块,它能读取 (当然也能写入) 磁盘上的 gzip 压缩文件。……那么怎么做来内存数据 (compresseddata) 创建类文件对象呢?这需要使用 StringIO 模块。
    (!) 值得注意的是,英文中的“OK”与中国人一般使用的“OK”意思不完全一样。“OK”的原义可表示让步,但中文中一般没有这种用法。

  4. 例11.15, (4):但 gzipper 还是真正的 {X} 从你用 StringIO 包装了压缩数据所创建的类文件对象中“读取”数据,……压缩的数据来自哪呢?你通常从远程 HTTP 服务器下载, (./) 最初

  5. 例11.16上:你在想那个 opener.open 返回一个类文件对象,那么为什么不抛弃中间件 StringIO 而通过 f 直接访问 GzipFile 呢?
    (./) 你在想,既然 opener.open 返回一个类文件对象,那么为什么不抛弃中间件 StringIO 而通过 f 直接访问 GzipFile 呢?

  6. 例11.16, (1):继续前面的例子,你已经有一个用 Accept-encoding: gzip 头信息设置的Request 对象。
    (./) 继续前面的例子,你已经有一个设置了 Accept-encoding: gzip 头信息的 Request 对象。

  7. 例11.16, (2):……这个数据已经被 gzip 压缩发送了
    (./) 这个数据被要求用 gzip 压缩发送(!) 从上下文看,此时还未发送数据。

  8. 例11.16, (3):从 opener.open 返回了一个类文件对象,并且阅读头信息你可以获知,……因为你从 GzipFile 实例“读取”,它将从远程 HTTP 服务器“读取”被压缩的数据并且立即解压缩。这是个好主意,但是不行的是它无法工作……所以使用 StringIO 这种看上去不雅的手段是最好的解决方案:下载压缩的数据,除此之外用 StringIO 创建一个类文件对象,……
    (./) 从 opener.open 返回了一个类文件对象,从头信息中你可以获知,……当你从 GzipFile 实例“读取”时,它将从远程 HTTP 服务器“读取”被压缩的数据并且立即解压缩。这是个好主意,但是不行……所以使用 StringIO 这种看上去不太优雅的手段是最好的解决方案:下载压缩的数据, StringIO 创建一个类文件对象,……
    (!) work 译为“工作”其实是很丑陋和无奈的译法,应当尽量避免出现。
    (!) “不太优雅”和“不雅”应该不是一个概念吧 :)

11.9 全部放在一起

  1. Para 1:你已经看到了构造一个职能 <!> 的 HTTP web 客户端的所有片断。 (./) 智能

  2. 例11.17, (1)urlparse is a handy utility module for, you guessed it, parsing URLs. It's primary function, also called urlparse,...
    urlparse 是一个解析 URL 的垂手可得的工具模块。它的主要功能也调用 urlparse,,获得一个 URL 并将其拆分为为一个包含 (scheme, domain, path, params, 查询串参数和验证片断) 的 tuple
    (./) urlparse 是一个解析 URL 的便捷的工具模块。它的主要函数也叫 urlparse,接受一个 URL 并将其拆分为 tuple (scheme (协议), domain (域名), path (路径), params (参数), query string parameters (请求字符串参数), fragment identifier (片段效验符))

  3. 例11.17, (6):使用两个自定义 URL 处理器创建一个 URL 开启器:SmartRedirectHandler 为了处理 301 和 302 重定向,而 DefaultErrorHandler 为了处理 304, 404 以及其它的错误条件。 (./) 用于

  4. 例11.17, (7):就 {i} 这样!

  5. 例11.18, (3):保存从服务器返回的 ETag hash,所以调用程序下一次能通过它返回给你,并且可以传递给 openAnything,连同 If-None-Match 头信息一起发送给远程服务器。
    (./) 保存从服务器返回的 ETag hash,这样主调程序下一次就能把它传递给你,然后再传递给 openAnything,放到 If-None-Match 头信息里发送给远程服务器。

  6. 例11.19, (1)真正 {X} 第一次获取资源时,你没有 ETag hash 或 Last-Modified 日期,……

  7. 例11.19, (3):……你需要更新你的 URL 到新地址(./) 你需要把你的 URL 更新为新地址

  8. 例11.19, (4):第二次获取相同的资源 {i} ,你已经从以往获得了各种信息:……

11.10 小结

  1. 每个客户端都应该支持的 5 个 HTTP web 服务重要特性
    (./) 每个客户端都应该支持 HTTP web 服务的以下 5 个重要特性

  2. 处理适当的永久重定向
    (./) 适当地处理永久重定向

8-3<X12>soap.xml SOAP web 服务

  1. Para 2:但解开这层面纱,SOAP 库实际上扮演了一个多 XML 文档和远程服务器参与的复杂处理过程。
    (./)揭开这层面纱,SOAP 库实际上执行了一个多 XML 文档和远程服务器参与的复杂处理过程。

  2. Para 3Some people would pipe up to add that SOAP allows for one-way asynchronous message passing, and document-oriented web services.
    有些人觉得应该补充上:SOAP 还允许单向异步的信息通过,并且是面向文档的 Web 服务。
    (./) 有些人觉得应该补充上:SOAP 还允许单向异步的信息通过,以及面向文档的 Web 服务。

12.1 概览

  1. Para 1:你是否曾经 {X} 希望能以程序化的方式访问 Google 的搜索结果呢?

  2. 进一步阅读The SOAP specification is surprisingly readable, if you like that sort of thing.
    SOAP 说明书对于 SOAP 相关的问题讨论非常易读
    (./) SOAP 规范相当可读,如果你喜欢这类东西的话

12.2 安装 SOAP 库

  1. 希望检验 XXX 安装是否正确,……
    (./) 检验 XXX 安装是否正确

  2. Para 3:你 {X} 要用到的第一个库是 PyXML, {i} 是 XML 库的一个高级组件,这个库 {X} 提供了比我们在 第 9 章 学习的 XML 内建库更多的功能。

  3. 12.2.2, Para 1:你所需要安装的第二个库是 fpconst,使 <!> 一系列支持 IEEE754 double-precision 特殊值的常量和函数,…… (./) 它是

12.3 步入 SOAP

  1. 例12.6, (1):你通过 SOAPProxy 这个 {i} 代理 (proxy) 类访问远程 SOAP 服务器。

  2. 例12.6, (2):每个 SOAP 服务都有一个命名空间(namespace),这个命名空间是由服务器任意命名的。这不过是为了调用 SOAP 方法而设置的。它使得服务器为多个不相关的服务提供服务 URL 和路径请求共享成为可能。这与 Python 中模块到 packages 的关系类似。
    (./) 每个 SOAP 服务都有一个命名空间(namespace),这个命名空间是由服务器任意命名的。这不过是为调用 SOAP 方法设置的。它使得服务器让多个不相关的服务共享服务 URL 和路径请求成为可能。这与 Python 中模块相对于包的关系类似。

  3. 例12.6, (3)You're creating the SOAPProxy with the service URL and the service namespace. This doesn't make any connection to the SOAP server; it simply creates a local Python object.
    这里你创建了包含服务 URL 和服务命名空间的 SOAPProxy。这与 SOAP 服务器无关;仅仅是建立了一个本地 Python 对象。
    (./) 这里你创建了包含服务 URL 和服务命名空间的 SOAPProxy。此时还不会连接到 SOAP 服务器;仅仅是建立了一个本地 Python 对象。

  4. 例12.6, (4):到此为止,如果你的设置完全正确,应该可以向调用本地函数一样调用远程 SOAP 方法。给普通函数传递参数并接收返回一样,但在这背后却隐藏着很多的工作。
    (./) 这和给普通函数传递参数并接收返回值一样,但在背后却隐藏着很多的工作。

12.4 SOAP 网络服务查错

  1. 显性数据类型”改为“显式数据类型”。

  2. “(Python) 原始数据类型”改为“本地数据类型”。

  3. 例12.7, (1):首先,正常建立带有服务 URL 和命名空间的 SOAPProxy。
    (./) 首先,和平常一样,建立带有服务 URL 和命名空间的 SOAPProxy。

  4. 例12.7, (3):最后,正常调用远程 SOAP 方法。
    (./) 最后,和平常一样,调用远程 SOAP 方法。

  5. 例12.7b, (1):这个元素名 getTemp 就是函数名。SOAPProxy 把 getattr 当作一个发报机有别使用方法名分别调用本地方法,这里使用方法名构造了一个 XML 请求文档。
    (./) 这个元素名 getTemp 就是函数名。SOAPProxy 使用 getattr 作为分发器有别于使用方法名分别调用本地方法,这里使用方法名构造了一个 XML 请求文档。

12.5 WSDL 介绍

  1. Para 1:它没有做到的是提供任何 {X} 方法自省的手段。

  2. Para 2试想一下:前面两部分所展现的调用只有一个参数和返回的简单远程 SOAP 方法。
    (!) 这不是假设。
    (./) 考虑一下:……

  3. Para 3:Python 精妙地 {X} 不需要明示类型,……

  4. Para 4:WSDL 是“网络服务描述语言(Web Services Description Language)”的缩写。 {i} 尽管是为自如地表述多种类型的网络服务而设定,却也经常用于描述 SOAP 网络服务。

  5. Para -6The type of web service (probably function calls using SOAP, although as I mentioned, WSDL is flexible enough to describe a wide variety of web services)
    网络服务的类型(可能还包括 SOAP 的函数调用,正像我所说过的,WSDL 足够自如地去描述网络服务的广泛内容)
    (./) 网络服务的类型(可能 SOAP 的函数调用,但我说过,WSDL 足够自如地去描述网络服务的广泛内容)

12.6 以 WSDL 进行SOAP 内省

  1. 例12.8, (2)To use a WSDL file, you again use a proxy class, WSDL.Proxy, which takes a single argument: the WSDL file. Note that in this case you are passing in the URL of a WSDL file stored on the remote server, but the proxy class works just as well with a local copy of the WSDL file.
    使用一个 WSDL 文件,你还是要用到一个 proxy 类:WSDL.Proxy,它只需一个参数:WSDL 文件。我所说的是把存储在远程服务器上的 WSDL 的 URL,但是这个 proxy 类对于本地的 WSDL 副本工作同样出色。
    (./) 使用一个 WSDL 文件,你还是要用到一个 proxy 类:WSDL.Proxy,它只需一个参数:WSDL 文件。我指定的是存储在远程服务器上的 WSDL 的 URL,但是这个 proxy 类对于本地的 WSDL 副本工作同样出色。

  2. 例12.8, (3):WSDL proxy 类以 Python 字典 server.methods 的方式揭示有效函数。所以列表有效方法就像调用字典方法 keys() 一样简单
    (./) WSDL proxy 类通过 Python 字典 server.methods 揭示有效函数。所以列出有效方法只需调用字典方法 keys()

  3. 例12.9, (3):在通过 SOAP 调用函数时,你不需要知道参数名,但 SOAP 支持在调用函数时使用参数名的情形 {X} (类似于 Python )。

  4. 例12.9, (4)Each parameter is also explicitly typed, using datatypes defined in XML Schema.
    每个参数都是都是显性类型的,在 XML Schema 中以数据类型定义
    (./) 每个参数都是都是显式类型的,使用的是在 XML Schema 定义的数据类型

  5. 例12.11, (1){i} 比直接调用 SOAP 服务时的设置简单,因为在 WSDL 文件中包含着调用服务所需要的服务 URL 和命名空间。

12.7 搜索 Google

  1. 过程12.4, 2.:还是在 http://www.google.com/apis/ 上,下载 Google 网络 APIs 开发工具包( {i} Google Web APIs developer kit)

  2. 例12.13上
    lr ( {i}language restrict”,语言限制) ie 和 oe ( {i}input encoding”,输入编码和 “output encoding”,输出编码)

  3. 例12.13, (1):……记住 {X} 要使用你注册 Google 网络服务时授权给你自己的 Google API 许可证。

  4. 例12.14, (2)In total, there were approximately 30 million results. You can access them 10 at a time by changing the start parameter and calling server.doGoogleSearch again.
    总共有接近30,000,000个结果信息,你可以通过以 10 递增地改变 start 参数来重复调用 server.doGoogleSearch 。
    (./) 总共有接近 30,000,000 个结果信息。通过让 start 参数以 10 递增来重复调用 server.doGoogleSearch,你能够获得全部的结果。

12.8 SOAP 网络服务故障排除

  1. Para 2:正如你在本章中看到的,SOAP 牵扯了很多层面。需要 HTTP 层,SOAP 需要向 HTTP 服务器发送 XML 文档并接收返回的 XML 文档。这样一来,你在 第 11 章 HTTP Web 服务 学到的差错技术在这里都有了用武之地。
    (./) 正如你在本章中看到的,SOAP 牵扯了很多层面。SOAP 向 HTTP 服务器发送 XML 文档并接收返回的 XML 文档时需要用到 HTTP 层。这样一来,你在 第 11 章 HTTP Web 服务 学到的调试技术在这里都有了用武之地。

  2. 例12.15, (2)The server responds by sending a SOAP Fault, which SOAPpy turns into a Python exception of type SOAPpy.Types.faultType. All errors returned from any SOAP server will always be SOAP Faults, so you can easily catch this exception. In this case, the human-readable part of the SOAP Fault gives a clue to the problem: the method element is not namespaced, because the original SOAPProxy object was not configured with a service namespace.
    服务器返回的是一个 SOAP 错误,SOAPpy 溢出了SOAPpy.Types.faultType 这个 Python 异常。从任何 SOAP 服务器返回的错误都是 SOAP 错误,因此你可以轻易地捕获这个异常。就此而言,我们能从 SOAP 错误信息中看出端倪:由于源 SOAPProxy 对象没有设置服务命名空间,因此方法元素也就没有了命名空间。
    (./) 服务器返回的是一个 SOAP 错误 (Fault),SOAPpy 把它转换为 Python 异常 SOAPpy.Types.faultType。从任何 SOAP 服务器返回的错误都是 SOAP 错误,因此你可以轻易地捕获这个异常。就此而言,我们能从 SOAP 错误信息中看出端倪:由于源 SOAPProxy 对象没有设置服务命名空间,因此方法元素也就没有了命名空间。

  3. 例12.16上Misconfiguring the basic elements of the SOAP service is one of the problems that WSDL aims to solve.
    错误配置 SOAP 服务的基本元素是 WSDL 问题解决的着眼点
    (./) 错误配置 SOAP 服务的基本元素是 WSDL 着眼解决的问题

  4. 例12.16, (1):……WSDL.Proxy 不会为你强制 {i} 转换数据类型;……

  5. 例12.18上What about Google's web service? The most common problem I've had with it is that I forget to set the application key properly.
    那么 Google 网络服务方面又如何呢?最常见的错误是我曾经犯过的忘记正确设置应用许可证错误。
    (./) 我曾经犯过的最常见的错误是忘记正确设置应用许可证。

  6. 例12.18Calling a Method With An Application-Specific Error
    调用方法返回一个应用指定错误
    (./) 调用方法返回一个应用特定的错误

  7. 例12.18, (1)The problem is application-specific: the first argument is supposed to be my application key,...
    问题在于应用指定:第一个参数应该是我的应用许可证,……
    (./) 这个问题是应用特定的:第一个参数应该是我的应用许可证,……

  8. 例12.18, (2)Google 服务器返回的是一个 SOAP 错误和一大串特别长的错误信息,其中包含了完整的 Java 堆栈跟踪。记住所有的 SOAP 错误都被标示为 SOAP 错误:设置错误,函数参数错误以及应用指定错误等等。在其中埋藏的至关重要信息确是非有效授权许可证:foo(Invalid authorization key: foo)
    (./) Google 服务器返回的是一个 SOAP 错误和一大串特别长的错误信息,其中包含了完整的 Java 堆栈跟踪。记住所有的 SOAP 错误都被标示为 SOAP Faults: errors in configuration (设置错误), errors in function arguments (函数参数错误),或者是应用特定的错误 (这里就是) 等等。在其中埋藏的至关重要信息Invalid authorization key: foo(非有效授权许可证:foo)

12.9 小结

  • pass

8-5<X13>roman.xml 单元测试

13.1 罗马数字介绍 II

  1. Para 1In previous chapters, you "dived in" by immediately looking at code and trying to understand it as quickly as possible. Now that you have some Python under your belt, you're going to step back and look at the steps that happen before the code gets written.
    在前面的章节中,你迅速“深入”并试图以最快的速度理解了这个程序。既然你已对 Python 有了一定的了解,那么接下来将回顾这个程序并从其代码被开发之前入手
    (./) 在前面的章节中,通过阅读代码,你迅速“深入”,以最快的速度理解了各个程序。既然你已对 Python 有了一定的了解,那么接下来让我们看看程序开发之前的工作

  2. roman.py 功能需求, 1.
    toroman 应该返回所有 1 到 3999 的罗马数字表示。
    (./) toroman 应该能返回 1 到 3999 中任意数的罗马数字表示。

13.2 深入

  • pass

13.3 romantest.py 介绍

  1. 根据前面章节的惯例,原标题介绍 romantest.py 改为 romantest.py 介绍

13.4 正面测试

  1. 列举, Para -1隔离运行,可以与其他测试用例隔离……
    (./) 独立运行,可以与其他测试用例隔离

  2. 例13.2, (1):编写测试用例首先需要写一个类来继承 unittest 模块中的 testcase 类,……
    (./) 编写测试用例的第一步就是继承 unittest 模块中的 testcase 类

  3. 例13.2, (3)Every individual test is its own method,...
    每个独立测试都是其自己的方法
    (!) of its own... 是常见的短语,仅表示“自身”的含义 (./) 每个独立测试本身都是一个方法

  4. 例13.2, (4)Also notice that you are not trapping any exceptions when you call toroman. This is intentional. toroman shouldn't raise an exception when you call it with valid input, and these input values are all valid. If toroman raises an exception, this test is considered failed. 同样值得注意,你在调用 toroman 时没有试图捕捉任何可能发生的异常。这正是我们所希望的。以有效输入调用 toroman 不会引发任何异常,因此这些输入都是有效的。如果 toroman 引发了异常,则测试被认为失败(输入是无效的)
    (./) 同样值得注意,你在调用 toroman 时没有试图捕捉任何可能发生的异常。这正是我们所希望的。以有效输入调用 toroman 不会引发任何异常,而你看到的这些输入都是有效的。如果 toroman 引发了异常,则测试失败
    (!) 不难判定孰正孰误。

13.5 负面测试

  1. 例13.3, (1):……使用 try...except block…… (./)

  2. 同上, Line -1:…… Python 中的任何事物都是对象 (!) 为了前文一致, (./) 万物皆对象

  3. 例13.3, (2):……不论是返回了一个值或者引发其他异常……
    (./) 不论是返回了一个值还是引发其他异常

  4. 例13.4上:要求 #4 与要求 #1 的处理方法相同,测试一个已知样本中的一个个数字对。要求 #5 与 #2 和 #3的处理方法相同,通过无效输入引发 fromroman 引发恰当的异常。
    (./) 要求 #4 与要求 #1 的处理方法相同,测试一个已知样本中的一个个数字对。要求 #5 与 #2 和 #3的处理方法相同,即通过无效输入确认 fromroman 引发恰当的异常。

  5. 例13.4, (1):……总计三个自定义异常需要在 roman.py 中定义
    (./) roman.py 中一共要定义三个异常

13.6 完备性测试

  1. 部分“回旋检查”改成“完备性测试”。
  2. Para 1:你经常会发现一组代码中包含互逆函数,它们通常是转换函数,……
    (./) 你经常会发现一组代码中包含互逆的转换函数

  3. 例13.5, (1):你已经见到过这个 {X} range 函数,……

  4. 例13.6上, Line -1:既然是有必要的规定,那么也就有必要测试。
    (./) 既然有必要规定,那么也就有必要测试。

  5. 例13.6, (1)The most interesting thing about this test case is all the things it doesn't test. It doesn't test that the value returned from toroman is right or even consistent; ...
    很有意思的是这个测试用例它并不测试什么。它所测试的不是 toroman 的返回值是否正确或者一致;……
    (./) 关于这个测试用例最有趣的一点不在于它测试了什么,而是它不测试什么。它不会测试 toroman 的返回值是否正确或者一致

  6. 同上:每个测试用例都应该只回答单一的问题。 (./) 每个测试用例只回答一个的问题。

  7. 例13.6, (2):每个测试用例必须可以与其他测试用例隔离 {X} 工作,……

8-6<X14>roman.xml 测试优先编程

  1. 本章标题Test-First Programming 以测试优先为原则的编程 (./) 测试优先编程
    (!) KISS 是改译的主要理由。../2006-03-22 中提出的“测试导向编程”也是个不错的名字,但我 Google 了一下,933:1,“测试优先编程”获胜。况且这样的译法并不少见(eg. broad-first search,广度优先搜索)。

  2. 频繁typo:他们 (./) 它们 (!) 怀疑是翻译时用了盲目的替换

14.1 roman.py, 第 1 阶段

  1. Para 1:到目前为止,单元测试已经完成,是时候开始编写被单元测试测试的代码的时候 {X} 了。但在逐步完成 roman.py 的同时你会看到它们一个个地通过测试 {X}

  2. 例14.1, (1):这 {i} 是如何定义你自己的 Python 异常。异常 {i} (Exception)也是类,通过继承已有的异常,你可以创建自定义的异常。

  3. 例14.2上Run romantest1.py with the -v command-line option, which will give more verbose output...
    运行 romantest1.py 带有 -v 选项的命令行可以得到更详细的输出信息,……
    (!) -_-明显不通。后面作了类似的改动。
    (./) 用命令行选项 -v 运行 romantest1.py 可以得到更详细的输出信息

  4. 例14.2Output of romantest1.py against roman1.py (./) 以 romantest1.py 测试 roman1.py 的输出

  5. 例14.2, (4)一个测试用例没能通过时,unittest 会区分是失败(failures)还是错误(errors)。
    (./) 当某个测试用例没能通过时,unittest 会区分是失败(failures)还是错误(errors)。

14.2 roman.py, 第 2 阶段

  1. 例14.5, (1)toroman does, in fact, always return uppercase, because romanNumeralMap defines the Roman numeral representations as uppercase. So this test passes already.
    toroman 通过,事实上其返回值总是大写的,因为 romanNumeralMap 定义的罗马字符都是以大写字母表示的。因此这个测试已经通过了。
    (./) 事实上,toroman 的返回值总是大写的,因为 romanNumeralMap 定义的罗马字符都是以大写字母表示的。因此这个测试已经通过了。

  2. 例14.5, (2):……以及可能的最长的罗马数字表示(3888 对应的(./) 对应于 3888

  3. 例14.5, (3)However, the function does not "work" for bad values;...
    但是,函数还没办法处理无效输入,……
    (!) 翻译成中文后,引号变得多余了。

14.3 roman.py, 第 3 阶段

  1. 例14.6, (2):……第二个参数是可选的,如果给定,则 {i} 在异常未被处理时显示于追踪信息(trackback)之中。

  2. 例14.8, (2):……当一个非整数传递给 toroman {i} ,int(n) <> n 检查出问题并引发 NotIntegerError 异常,……

  3. Para -1When all the unit tests for an entire module pass, stop coding the module.
    一旦一个完整模块的单元测试通过了,停止编写这个模块。
    (./) 一旦整个模块的单元测试通过了,停止编写这个模块。

14.4 roman.py, 第 4 阶段

  1. 例14.9, (1):这和 toroman 的工作模式很相像(./) 相似

  2. 例14.11, (2):尚不能完全相信,理论上存在这种可能性:toroman 存在错误而导致一些特定输入产生错误罗马数字表示 fromroman 存在相应的错误,把 toroman 错误产生的这些罗马数字错误地转换为最初的整数。
    (./) 尚不能完全相信,理论上存在这种可能性:toroman 存在错误而导致一些特定输入会产生错误的罗马数字表示,并且 fromroman 存在相应的错误,把 toroman 错误产生的这些罗马数字错误地转换为最初的整数。

14.5 roman.py, 第 5 阶段

  1. 罗马数字规则, 2.:44 表示为 XLIV (比50小10, <!> 比 5 小 1) (./) 加上

  2. 4.有五个字符不能被重复:
    (./) 含五的字符不能被重复:
    (!) 还请参看 re 一章。

  3. 5.:罗马数字经常 <!> 从高位到低位书写 (./) 一般

  4. 例14.13, (2)More importantly, the bad input tests pass. For instance, the malformed antecedents test checks cases like MCMC.
    更重要的是,无效输入测试也通过了。例如,前面那个测试用例需要检查 MCMC 之类的情形。
    (./) 更重要的是,无效输入测试也通过了。例如,上面这个用例测试了 MCMC 之类的情形。

  5. 例14.13, (3):正则表达式捕捉了所有 {X} 你在编写测试用例时所能预见的所有情况。

8-7<X15>roman.xml 重构

  1. 频繁typo:他们 (./) 它们 (!) 这个和上一章一样

15.1 处理 bugs

  1. 例15.1, (1):在前面的章节中你注意到一个空字符串会匹配 {i} 那个检查罗马数字有效性的正则表达式了吗?

  2. 例15.5, (1):空字符串测试用例现在通过了,说明 Bug 被改正 <!> 了。 (./) 修正 (!) “改正” bug……怎么读怎么不通

  3. Para -1Coding this way does not make fixing bugs any easier. Simple bugs (like this one) require simple test cases; complex bugs will require complex test cases. In a testing-centric environment, it may seem like it takes longer to fix a bug, since you need to articulate in code exactly what the bug is (to write the test case), then fix the bug itself.
    这样编程,并没有令 Bug 修正变得简单。简单的 Bug (就像这一个)需要简单的测试用例,复杂 Bug 则需要复杂的测试用例。在测试为核心的氛围下,这好像延长了修正 Bug 的时间,因为你需要先贴切地描述出 Bug (编写测试用例)然后才去修正它。
    (./) 这样编程,并没有令 Bug 修正变得简单。简单的 Bug (就像这一个)需要简单的测试用例,复杂 Bug 则需要复杂的测试用例。以测试为核心的氛围好像延长了修正 Bug 的时间,因为你需要先贴切地描述出 Bug (编写测试用例)然后才去修正它。

  4. 同上:而且,由于任何新的更改后你都可以轻易地重新运行所有测试用例,新代码破坏老代码的机会也变得微乎其微。
    (./) 而且不论如何更改,你都可以轻易地重新运行所有测试用例,新代码破坏老代码的机会也变得微乎其微。

15.2 应对需求变化

  1. 例15.8, (1):你不需要改变函数的其他部分,它们已经适用于新的情况。(它们会欣然地为新的 1000 添加 'M',以 4000 为例,他们 <!> 会返回 'MMMM' ) (!) 这里再说“它们”就不通了 (./) 函数

  2. 例15.8, (2):这就允许最多 4 个 M 字符而不再是 3 个,意味着你允许 {X} 代表 4999 而不是 3999 的罗马数字。

15.3 重构

  1. Para 2:重构是在可运行代码的基础上使之更良好工作的过程
    (./) 重构是在可运行代码的基础上使之工作得更好的过程

  2. 例15.10, (1)This is the syntax you've seen before: re.search takes a regular expression as a string...
    这是你曾在 re.search 中看到的语法。……
    (./) 这是你看到过的 re.search 语法

  3. 例15.10, (3):re.compile 返回 {i} 已编译的 pattern 对象有几个值得关注的功能:……

  4. 例15.14, (2)This is not a license to endlessly tweak your code just for the sake of tweaking it;...
    这并不是给只是为了调整代码而无休止地调整以许可,……
    (./) 这并不是给无休止地为了调整代码而调整代码以许可;……
    (!) 突出了for the sake of

  5. 例15.15, (1)The re.compile function can take an optional second argument, which is a set of one or more flags that control various options about the compiled regular expression.
    re.compile 函数的第二个参数是可选的,这个参数通过一个或一组选项设置来控制预编译正则表达式的多样化选项
    (./) re.compile 函数的第二个参数是可选的,这个参数通过一个或一组标志(flag)来控制预编译正则表达式的选项

  6. 例15.16, (1):新“verbose”版本和老版本的运行速度一样。事实上,编译的 pattern 对象也一样,因为 re.compile 函数 {i} 剔除掉所有你添加的内容。

15.4 后记

  1. Para 1The biggest headache (and performance drain) in the program as it is currently written is the regular expression, which is required because you have no other way of breaking down a Roman numeral.
    现在写的这个程序中最令人头痛(性能负担)的是正则表达式,它是必需的,因为没有其它方法来处理罗马数字。
    现在写的这个程序中最令人头痛的性能负担是正则表达式,但它是必需的,因为没有其它方法来识别罗马数字。

  2. Para -1And unit tests can give you the confidence to do large-scale refactoring... even if you didn't write the original code.
    并且单元测试给了你大规模重构的信心……既便没写出原有的代码也是这样
    (./) 并且单元测试给了你大规模重构的信心……即使原有的代码不是你写的

15.5 小结

  1. Para 8:为 {X} 改进性能、可伸缩性、可读性、可维护性和任何缺少的特性而无情地重构。

8-9<X16>regression.xml 函数编程

  1. 本章标题:存在多年的问题,Functional Programming 有效编程 (./) 函数编程

  2. “退化测试”和前面的“回归测试”都是好名字。我又一次把选择权交给了 Google……191,000 : 1,890,000,“回归测试”获胜。
    • “回归”是标准的数学用语(eg. linear regression线性回归),而“退化”好像……

  3. sample 一律译为“样例”。

    • 原译“范例”,给人的感觉好像 Mark 写的程序就是样板了;
    • 和前面章节一致。
  4. 为和前面章节一致,list comprehension 一律译为“列表解析”(原译“列表遍历”),list mapping 一律译为“列表映射”(原译“列表关联”)。

  5. 为和前面章节一致,标题中出现的“介绍XXX”一律改为“XXX介绍”。
  6. 频繁 typo:
    • 倒入 (./) 导入

16.1 概览

  1. Para 1:……你看到单元测试如何令大规模重组 <!> 变得容易 (./) 重构

  2. Para 2I actually use this script as part of the build process for this book; I have unit tests for several of the example programs
    ……实际上这是我构建本书自身代码的一部分。我为几个样例程序都编写了单元测试。
    (./) 实际上这是本书的构建代码的一部分;……

  3. 例16.2上:把这段代码放在本书其他样例代码相同的目录下运行之,模块 test.py <!> 中的所有单元测试将被找到并一起被运行。 (./) moduletest.py

  4. 例16.2, (2)The next 5 tests are from...
    接下来的五个代码来自于…… (./) 测试 (!) (3)中作类似修改。

16.2 找到路径

  1. Para 1:从命令行运行 python 代码时,知道所运行代码 {X} 在磁盘上的存储位置有时候是有必要的。

  2. Para 2This 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 处理 中看到的,它包含了很多命令行参数。它也同样记录了运行脚本的名字,和你调用它时使用的命令一摸一样。这些信息足以令我们确定文件的位置。
    (!) 后面多处作了与第二点类似的修改。

  3. 例16.3, (3):os.path.abspath 是这里的关键。它接受的路径名可以是部分的甚至是完全空白,却返回完整有效的路径名
    (./) ……但总能返回完整有效的路径名。

  4. 例16.4, (2)一个空字符串调用 os.path.abspath 当前的工作路径,与 os.getcwd()的效果相同。
    (./) 用空字符串调用 os.path.abspath 将返回当前的工作路径,……

  5. 例16.5上:……这意味着如果你正工作于 /usr/ 目录,os.path.abspath('bin/../local/bin') 将会返回 /usr/local/bin。它以尽可能简单的方式格式化路径名。
    (./) 它把路径名格式化为尽可能简单的形式。

  6. 例16.5, (2):如果脚本是以不完整路名被运行的,sys.argv[0] 还是会包含命令行中 {X} 出现的一切。

  7. Para -1This 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 重识列表过滤

  1. 本节标题Filtering lists revisited
    过滤已访问列表 (./) 重识列表过滤

  2. 例16.7, (4):你可以通过 for 循环的方式完成相同的工作。根据你编程的背景,……
    (./) 取决于你的编程背景

  3. 例16.8, (2)This is a compiled regular expression.
    一个复杂的正则表达式。
    (./)一个预编译的正则表达式。

  4. 同上:编译后的对象将含有接受一个被寻找 <!> 字符串作为参数的 search 方法。 (./) 待寻找

16.4 重识列表映射

  1. 本节标题Mapping lists revisited
    关联已访问列表 (./) 重识列表映射

  2. 例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 则古老得多

  3. 例16.10, (3):你如果坚持以 Visual Basic 程序员 {X} 自居,通过 for 循环的方法完成相同的任务也完全可以。

  4. 例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 是一个接受文件名,剥离出其扩展名,然后只返回文件名称的函数

  5. 例16.12, (2)调用它 map 接受files列出的所有文件名,把它传递给 filenameToModuleName 函数,并且返回每个函数调用结果所组成的列表。
    (./) 调用 map 将把 files 列出的所有文件名传递给 filenameToModuleName 函数,并且返回每个函数调用结果所组成的列表。

  6. Para -1:如你在本章剩余部分将看到的,你可以将这种数据中心思想扩展应用 {X} 到定义和执行一个容纳来自很多单个测试套件的测试的一个测试套件的最终目标。

16.5 数据中心思想编程

  1. Para 2:这就是关键的一步,使你有了被处理 <!> 的真实数据:文件名列表。 (./) 待处理

  2. Para 3:你有太多数据,因此你需要 {i} 过滤( filter 数据。

  3. Para 4:现在你有了每个测试套件的文件名(且局限于测试套件,因为所有其他内容都被过滤掉了),但是你确实 {X} 还需要以模块名来替代之。

  4. Para 5:但是 for 循环看起来像是个繁重的工作。至少,简单讲是在浪费时间,糟糕的话还会隐埋错误( {X} Bug比方说,你需要弄清楚如何测试这样一个条件“这个文件是测试套件吗?”不管怎么说,这是应用细化逻辑,没有哪个语言可以让我们这样做。但是一旦你搞清楚了,你还需要费尽周折的定义一个新的空列表、写一个 for 循环以及一个 if 语句并手工地调用 append 将符合条件的元素一个个添加到新列表中,然后一路注意区分那个变量里放着过滤后的数据,那个变量里放着未过滤得老数据吗? {X}
    (./) 例如,你需要弄清楚如何测试这样一个条件:“这个文件是测试套件吗?”这是应用特定的逻辑,没有哪个语言能自动为我们写出其代码

  5. Para -2I 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 语句以及一步步地以代码为中心的编程方式

  6. Para -1:让这一切都远去吧。费力不讨好的编程不重要,数据重要。并且数据并不难,他们不过就是数据。
    (./) 并且数据并不麻烦它们不过就是数据。

16.6 动态导入模块

  1. Para 2The 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 语法查看搜索路径,根据给定的名字寻找模块并导入它们。你甚至可以这样做:以逗号分割同时导入多个模块,本章代码前几行就是这样做的。

  2. 例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 的结果完全相同。
    (!) 后面作类似修改。

  3. 例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__ 导入一个模块,但是是通过一个字符串参数来做到的。依此处讲,你用以导入的仅仅是一个硬编码性的字符串,但它可以是一个变量,或者一个函数调用的结果。

  4. 例16.15Importing a list of modules dynamically
    动态导入一个列表锁定的模块 (./) 动态导入模块列表

  5. 例16.15, (2)令人惊奇,你需要导入他们,且通过关联 __import__ 到列表实现了。
    (./) 简单得令人惊奇,通过映射 __import__ 就实现了导入。

  6. Para -1:现在,你应该能够把这一切放在一起 {i} 并能搞清楚本章大部分样例代码 {X} 是做什么的。

16.7 全部放在一起

  1. 例16.16下As you saw in Section 16.2 Finding the path, the script directory will end up in the path variable,...
    正如在 第 16.2 节 “找到路径” 中所见,脚本目录将最终 {X} 存于 path 变量,……

  2. 例16.18, (3):剩下的是一个单元测试脚本列表,因为只有它们是 {i} 形如 SOMETHINGtest.py 的文件。

  3. 例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 语句定义的普通函数神奇。

  4. 例16.20, (2):modules 现在是一个模块列表,像其他模块一样可用
    (./) modules 现在是一个模块列表,其中的模块和其他模块一样

  5. 例16.21Step 5: Loading the modules into a test suite
    步骤 5:将模块调入 <!> 测试套件 (./) 载入

  6. 例16.21, (1):这正是 loadTestsFromModule 方法的工作:内省每一个模块并为每个模块返回一个 unittest.TestSuite 对象。每个 TestSuite 对象实际上 {X} 都包含了一个 TestSuite 对象列表,每个对象对应着你的模块中的一个测试方法。

  7. 例16.21, (2):把 TestSuite 的中文名说明移至第一次出现的地方,例16.21, (1)

  8. 例16.21下:自省过程是 unittest 模块经常为我们做的一项工作。还记得我们的独立测试模块调用并大刀阔斧地完成一起工作的那个看似神奇的 unittest.main() 函数吗
    (./) 自省过程是 unittest 模块经常为我们做的一项工作。还记得我们的独立测试模块仅仅调用了看似神奇的 unittest.main() 函数就大刀阔斧地完成了全部工作吗

  9. 例16.22, (1):你已经创建了一个自己就能导入模块、调用 unittest.defaultTestLoader 并封装于一个测试套件的(regressionTest)函数。现在你所要做的不是去寻找测试并以通用的方法构建一个测试套件,而是告诉 unittest 前面那些,它将调用返回可以直接使用的 TestSuite 的 regressionTest 函数
    (./) 在不使用 unittest 模块来为我们做这一切的神奇工作的情况下,你实际上已自己做到了。你已经创建了一个自己就能导入模块、调用 unittest.defaultTestLoader 并封装于一个测试套件的 regressionTest 函数。现在你所要做的不是去寻找测试并以通用的方法构建一个测试套件,而是告诉 unittest 前面那些,它将调用 regressionTest 函数,而它会返回可以直接使用的 TestSuite

16.8 小结

  1. 不使用列表遍历的情况下 {X} ,使用 filter 过滤列表。

  2. 在不使用列表遍历的情况下,使用 map 关联列表。
    (./) 不使用列表解析,使用 map 映射列表。

8-17<X17>plural.xml 动态函数

  1. 为和前面章节一致,“介绍 XYZ”一律改为“XYZ 介绍”。

17.1 概览

  1. Para 4下, 复数规则介绍, 1.
    If a word ends in S, X, or Z, add ES. "Bass" becomes "basses",...
    如果一个词以 S, X, Z, 或者 ES 结尾,“Bass” 变成 “basses”,……
    (./) 如果一个词以 S, X 或 Z 结尾,加 ES。如 “Bass” 变成 “basses”,……

  2. 同上, 2.If a word ends in a noisy H, add ES; if it ends in a silent H, just add S.
    如果一个词以发音的 H 加 ES 结尾,或以不发音的 H 加 S 结尾。
    (./) 如果一个词以发音的 H 结尾,加 ES;若以不发音的 H 结尾,加 S。

17.2 plural.py, 第 1 阶段

  1. Para 1:你所针对的单词,至少在英语中是字符串和字符。另外你需要规则来找出不同的字符(字母)组合,并对他们进行不同的操作。
    (./) 你所针对的单词(至少在英语中)是字符串和字符。你需要规则来找出不同的字符(字母)组合,并对它们进行不同的操作。

  2. 例17.1, (2):re.sub 函数起着 <!> 以正则表达式为基础的替换工作。让我们更具体地看看它。 (./) 进行

  3. 例17.5, (1):正则表达式把 vacancy 变为 vacancies,把 agency 变为 agencies {i} ,这正是你想要的。

17.3 plural.py, 第 2 阶段

  1. 例17.6, (3):rules 包含函数:不是指函数名,而是指函数本身。当他们被赋予给 for 循环中,matchesRule 和 applyRule 就成了你可以调用的真正函数。
    (./) 当 matchesRule 和 applyRule 在 for 循环中被赋值后,它们就成了你可以调用的真正函数。

17.4 plural.py, 第 3 阶段

  • pass

17.5 plural.py, 第 4 阶段

  1. 例17.9, (1)buildMatchAndApplyFunctions is a function that builds other functions dynamically. It takes pattern, search and replace (actually it takes a tuple, but more on that in a minute)...
    buildMatchAndApplyFunctions 是一个动态生成其它函数的函数。它将 pattern,search 和 replace (实际上是一个元组,但很快就会变得不止于此
    (./) 我们很快就会提到这一点

  2. 例17.9, (2):你实际上是在应用规则函数中定义常数:接受一个参数(word),但随后它与定义应用规则函数时设置的另外两个值 (search 和 replace)一起工作
    你实际上是在应用规则函数中定义常量:它只接受一个参数(word),但用到了定义时设置的两个值 (search 和 replace)

  3. 例17.9, (3):最终,buildMatchAndApplyFunctions 函数返回一个包含两个值的元组:你刚刚创建的两个函数。你在这些函数中定义的 {i} 常量(matchFunction 中的 pattern 以及 applyFunction 中的 search 和 replace)保留在这些函数中,……

  4. 例17.13, (1):注意到双括号了吗?这个函数并不是真的接受三个参数,实际上只接受一个参数:一个三元素元组。但是在函数被调用时元组概念 {X} 被展开了,元组的三个元素也被赋予了不同的变量……

  5. Para -1Using map to map a single list onto a function always calls the function with a single parameter: each element of the list. In the case of patterns, each element of the list is a tuple, so buildMatchAndApplyFunctions always gets called with the tuple,...
    使用 map 映射一个列表到函数时,通常使用单参数:列表中的每个元素。就 patterns 而言,列表的每个元素都是一个元组,所以 buildMatchAndApplyFunctions 经常是以元组来调用, (./) 总是

17.6 plural.py, 第 5 阶段

  1. Para 1First, let's create a text file that contains the rules you want. No fancy data structures, just space- (or tab-)delimited strings in three columns.
    首先,让我们建立一个包含所有你需要的规则的文本文件。没有什么特别的结构,不过是以空白 <!> (或者制表符)把字符串列成三列。 (./) 空格

  2. 例17.16, (1)You're still using the closures technique here (building a function dynamically that uses variables defined outside the function), but now you've combined the separate match and apply functions into one. (The reason for this change will become clear in the next section.) This will let you accomplish the same thing as having two functions, but you'll need to call it differently, as you'll see in a minute.
    在这里你还将使用闭合技术(动态构建函数时使用函数外部定义的变量),但是现在你把原来分开的匹配函数和规则应用函数合二为一。(你将在下一节中明了其原因) 你很快会看到,这与分别调用两个函数效果相同。
    (./) 在这里你还将使用闭合技术(动态构建函数时使用函数外部定义的变量),但是现在你把原来分开的匹配函数和规则应用函数合二为一(你将在下一节中明了其原因)。你很快会看到,这与分别调用两个函数效果相同,只是调用的方法稍有不同

  3. 例17.16, (5):当返回的函数被调用,则将执行 re.search('[sxz]$', word) 和 re.sub('$', 'es', word)
    (./) 当返回的函数被调用,则将执行 re.search('[sxz]$', word) and re.sub('$', 'es', word)

17.7 plural.py, 第 6 阶段

  1. 例17.18, (1):make_counter 中出现关键字 yield 意味着这不是一个普通的函数。它是一种每次生成一个值的特殊函数。你可以把它看成是一个可恢复函数。调用它会返回一个生成器,它可以返回 x 的连续 {i}

  2. 例17.19下So you have a function that spits out successive Fibonacci numbers. Sure, you could do that with recursion, but this way is easier to read.
    这样你就有了成功生成 Fibonacci 数的函数了。当然你也可以通过递归做到,但是这里的方法更加容易和理解
    (./) 这样你就有了生成连续的 Fibonacci 数的函数了。然你也可以通过递归做到,但是这里的方法更加易读

  3. 例17.20, (1):for 循环将会创建一个生成器对象并成功 <!> 调用其 next() 方法获得值并赋予 for 循环变量(n)。 (./) 连续

17.8 小结

  • pass

8-18<X18>soundex.xml 性能优化

Great bug!

  1. stage2 中采用的“目前最佳方案”是 1c,实际应为 1e。文中给出的代码也都是采用 1c 的方案,但实际文件中采用的是 1e 的方案。已修正。

  2. stage 2stage 3 中给出的 2c 的性能测试结果相差甚远。取 stage 2 中的结果,因为它比 stage 3 中的结果数值上均小,且这样处理后能稍微减轻测试结果与正文不符的情况。

  3. 多处对各程序性能的比较与作者给出的参考测试结果不符。具体可以参见下图(m$paint 画 di :) )。黑色箭头代表文中所说的性能关系(a -> b <=> a 比 b 慢),反向的蓝色和红色箭头表示测试数据与其矛盾,旁边的数字表示测试点(1. Woo, 2. Pilgrim, 3. Flingjingwaller)其中蓝色表示矛盾,但两个数据本来相差就较小;而红色表示完全相反。
    未修正。XiaQ 的测试结果也和正文不甚吻合。暂缀译注提醒读者。先慢慢联系 Mark Pigrim,等他重写本章后再同步修正。

stage0.jpg stage1.jpg

18.1 概览

  1. Para 5:哦,是的,单元测试。不必我说,在开始性能优化之前你需要一个完全的单元测试集。你需要的最后一件事情就是在乱动你的算法时引入新的问题。
    (./) 你最不需要的就是在乱动你的算法时引入新的问题。

  2. Para 6With these caveats in place, let's look at some techniques for optimizing Python code. The code in question is an implementation of' the Soundex algorithm.
    谨记着这些忠告,让我们来看一些优化 Python 代码的技术。我们要研究的代码是实施 Soundex 算法
    (./) 我们要研究的代码是 Soundex 算法的实现

18.2 使用 timeit 模块

  1. Para -2:Python 有一个方便的 min 函数可以把输入的列表返回成最小值
    (./) Python 有一个方便的 min 函数返回输入列表中的最小值

  2. Para -1:如果你有一个很大的 Python 程序并且不知道你的性能问题所在, {X} 查看 hotshot 模块。

18.3 优化正则表达式

  1. Para 1Regular expressions are almost never the right answer; they should be avoided whenever possible. Not only for performance reasons, but simply because they're difficult to debug and maintain. 正则表达式几乎永远不是最好的答案,而且应该被尽可能避开。这不仅仅是基于性能考虑,而是因为差错 <!> 和维护都很困难,…… (./) 调试

  2. Para 4How does soundex1a.py perform? For convenience, the __main__ section of the script contains this code that calls the timeit module, sets up a timing test with three different names, tests each name three times, and displays the minimum time for each:
    soundex1a.py 表现如何?为了方便,__main__ 部分的代码包含了调用 timeit 模块,建立一个分别测试三个不同名字三次并显示最短耗时的一个计时测试代码
    (./) soundex1a.py 表现如何?为了方便,__main__ 部分包含了一段代码:调用 timeit 模块,为三个不同名字分别建立测试,依次测试,并显示每个测试的最短耗时

  3. Para 7:Woo 是个……小样本;Pilgrim 是个……正常样本;Flingjingwaller 是……特别长的样本。其它的测试可能同样有帮助,但它们已经是很好的不同样本范围了
    (./) 但它们已经很好地代表了不同的样本范围。

  4. Para -7But is this the wrong path? The logic here is simple: the input source needs to be non-empty, and it needs to be composed entirely of letters. Wouldn't it be faster to write a loop checking each character, and do away with regular expressions altogether? 但是这样的优化是正路吗?这里的逻辑很简单:输入 source 应该是非空,并且需要完全由字母构成。如果编写一个循环查看每个字符并且与正则表达式一同工作是否会更快些? (./) 如果编写一个循环查看每个字符并且抛弃正则表达式,是否会更快些?

18.4 优化字典查找

  • pass

18.5 优化列表操作

  1. Para 6soundex3a.py does not run any faster than soundex2c.py, and may even be slightly slower (although it's not enough of a difference to say for sure):
    soundex3a.py 并不比 soundex2c.py 运行得快 {i} 多少,而且甚至 {i} 可能会更慢些(差异还没有大到可以确信这一点):
    (./) 有趣的是,结果表明 soundex3a.py 并不比 soundex2c.py 慢 (快那么一点点),不这样加就说不同了。

  2. Para 7:为什么 soundex3a.py 不更快呢?其实 Python 的索引功能恰恰很有效。重复使用 digits2[-1] 根本没什么问题。另一方面,手工另外保留上一个数字为另外的变量意味着我们存储的每个数字的 两个 变量赋值,这便抹杀了我们避开索引查找所带来的微小好处。
    (./) 另一方面,手工保留上一个数字意味着我们每存储一个数字都要为 两个 变量赋值……

  3. Para -4 Instead of incrementally building a new list (or string) out of the source string, why not move elements around within a single list? 与其一砖一瓦地建造一个新的列表(或者字符串),为什么不在一个列表中移动元素
    (./) 其一砖一瓦地建造一个新的列表(或者字符串),为什么不选择操作列表的元素呢
    (!) 就下文使用的方法来看,move around 指的仅仅是一般意义的“改动”,而不是“移动”。

  4. Para -1:我们在这儿除了试用了几种 “clever <!> ” 的技术,根本没有什么进步。 (./) 聪明

18.6 优化字符串操作

  1. Para -5:我们早就知道我们需要把结果截成四字符,并且我们知道我们已经有了一个没有改变的字符(起始字符从 source 中不作改变的拿过来)。这意味着我们可以仅仅在输出的结尾添加三个零,然后截短它。
    (./) 我们早就知道我们需要把结果截成四字符,并且我们知道我们已经有了至少一个字符(直接从 source 中拿过来的起始字符)。这意味着我们可以仅仅在输出的结尾添加三个零,然后截断它。

18.7 小结

  1. Para -1:最后一点太重要了,这章中你令这个程序三倍的提速并且另百万次的调用节省 20 秒。
    (./) 最后一点太重要了,这章中你令这个程序提速三倍并且令百万次的调用节省 20 秒。

  1. 见《现代汉语词典》。 (1)

DiveIntoPythonZh/xn (last edited 2009-12-25 07:17:15 by localhost)