1. 2006-03-24 校对记要

校对文件: roman.xml

章节第14章

1.1. 第14章第2节 roman.py, 第2阶段

http://www.woodpecker.org.cn/obp/diveintopython-zh-5.4/zh-cn/dist/htmlflat/diveintopython.html#roman.stage2

第3行

  • This file is available in py/roman/stage2/ in the examples directory.
  • 这个程序可以 <!>在例子目录下的 py/roman/stage2/ 的 examples 目录中 <!> 获得 找到

JasonXie 同意


Example 14.3 的注释1第1句

  • romanNumeralMap is a tuple of tuples which defines three things:
  • romanNumeralMap 是一个 <!> 用来定义三个内容的元组的元组 元组的元组,定义了三方面的内容

JasonXie 同意


Example 14.3 的注释1第1点

  • 1.The character representations of the most basic Roman numerals. Note that this is not just the single-character Roman numerals; you're also defining two-character pairs like CM (“one hundred less than one thousand”); this will make the toRoman code simpler later.
  • 1. <!> 代表大部分罗马数字 <!> 字符。 注意不只是 <!> 罗马数字的单字符 单字符的罗马数字,你同样在这里定义诸如 CM (“ <!> 比一千少一百 表示900”)的双字符,这可以 <!>稍后编写的 toRoman 简单一些。

JasonXie 同意


Example 14.3 的注释1第2点

  • Here's where your rich data structure pays off, because you don't need any special logic to handle the subtraction rule.
  • 这里便显示出你丰富的数据结构带来的优势,你不 <!> 必处理 需要什么特定的逻辑 <!> 处理减法规则。

JasonXie 同意


Example 14.5.

  • Example 14.5. Output of romantest2.py against roman2.py
  • <!>romantest2.py 测试 roman2.py 的 <!> 输出 结果

JasonXie 无伤大雅,osmond统稿时如果决定修改注意书中有多次相同的句式,应一并修改


Example 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 通过,事实上所有返回值都是大写的 事实上toRoman 的返回值总是大写的,因为 romanNumeralMap 定义的罗马字符都是以大写字母表示的。 因此这个测试已经通过了。

JasonXie 同意


Example 14.5.输出的注释2

  • Here's the big news: this version of the toRoman function passes the known values test. Remember, it's not comprehensive, but it does put the function through its paces with a variety of good inputs, including inputs that produce every single-character Roman numeral, the largest possible input (3999), and the input that produces the longest possible Roman numeral (3888). At this point, you can be reasonably confident that the function works for any good input value you could throw at it.
  • <!> 这有个大新闻 好消息来了 :这个版本的 toRoman 函数能够通过 已知值测试。 记住,这并不能证明完全没问题,但至少 <!> 已经通过了大量的测试 通过测试多种有效输入考验了这个函数:包括 <!> 生成每个单一 <!> 罗马数字字符字符的罗马数字<!> 最大可能可能的最大输入(3999),以及 <!> 可能的最长的罗马数字表示(3888 对应的) 。从这点来看,你可以有理由 <!> 自信的人为 相信这个函数对于任何有效输入 <!> 不会出问题。

  • {i} put sth. through his paces. 考查某人[某物]的本领[性能], 考验某人[某物]是否合用. 固定用法。

JasonXie 同意


Example 14.5.输出的注释3

  • However, the function does not “work” for bad values; it fails every single bad input test. That makes sense, because you didn't include any checks for bad input. Those test cases look for specific exceptions to be raised (via assertRaises), and you're never raising them. You'll do that in the next stage.
  • 但是,函数 <!> 对无效输入仍然不 “起作用”还没办法处理无效输入,每个 无效输入测试 都失败 <!> 。 这 <!> 可以 很好理解 , <!> 因为你还没有对无效输入进行检查 <!>。 <!> 独立测试 (!) 测试用例 (!) 希望捕捉到特定的异常(通过 assertRaises),而你根本没有让这些异常引发。 这是你下一 <!>阶段的工作。

JasonXie 同意


最后一句

  • Here's the rest of the output of the unit test, listing the details of all the failures. You're down to 10.
  • <!>下面是单元测试结果的剩余部分,列出了所有的失败 <!>的详细信息。你已经让它降到了10个 <!>

  • {i} 句尾少了一个句号 :)

JasonXie 同意

1.2. 第14章第3节 roman.py, 第3阶段

http://www.woodpecker.org.cn/obp/diveintopython-zh-5.4/zh-cn/dist/htmlflat/diveintopython.html#roman.stage3

Example 14.6. roman3.py

  • This file is available in py/roman/stage3/ in the examples directory.
  • 这个程序可以 <!>在例子目录下的 py/roman/stage3/ 的 examples 目录中 <!> 获得 找到

JasonXie 同意


程序注释1

  • This is a nice Pythonic shortcut: multiple comparisons at once. This is equivalent to if not ((0 < n) and (n < 4000)), but it's much easier to read. This is the range check, and it should catch inputs that are too large, negative, or zero.

  • <!> 这是 Python 的一个很棒的缩写 这个写法很Pythonic<!> 多重比较可以写在一起一次进行多个比较。 这等价于if not ((0 < n) and (n < 4000)), 但是 <!> 读起来简单了很多更容易让人理解。这是 <!> 一个在进行范围检查,可以将过大的数,负数和零查出来。

JasonXie 同意。可否译作:这是一个很棒的Python缩写


程序注释2最后一句

  • if given, it is displayed in the traceback that is printed if the exception is never handled.
  • 如果给定,则在异常未被处理时显示于追踪 <!> 信息(trackback)之中。

JasonXie 同意


Example 14.7. Watching toRoman handle bad input

  • <!> 查看观察toRoman <!> 如何处理无效输入

JasonXie 同意


Example 14.8. Output of romantest3.py against roman3.py

  • <!>romantest3.py 测试 roman3.py 的 <!> 输出 结果

JasonXie 同意


输出结果说明1

  • toRoman still passes the known values test, which is comforting. All the tests that passed in stage 2 still pass, so the latest code hasn't broken anything.
  • toRoman 仍然能通过 已知值测试,这令人 <!> 很舒服 鼓舞。 所有 <!> 第 2 步 在第2阶段通过的测试 <!>仍然能通过<!> 也就是说这说明新的代码没有对原有代码构成任何负面影响。

JasonXie 同意


输出结果说明2第1句

  • More exciting is the fact that all of the bad input tests now pass. This test, testNonInteger, passes because of the int(n) <> n check. When a non-integer is passed to toRoman, the int(n) <> n check notices it and raises the NotIntegerError exception, which is what testNonInteger is looking for.

  • 更令人振奋的是所有的 无效输入测试 现在都通过了。 <!> 测试 testNonInteger testNonInteger 这个测试 能够通过是因为有了 int(n) <> n 检查。

JasonXie 同意


输出结果说明3

  • This test, testNegative, passes because of the not (0 < n < 4000) check, which raises an OutOfRangeError exception, which is what testNegative is looking for.

  • <!> 测试 testNegativetestNegative这个测试 能够通过 <!> 适应为是因为,当 not (0 < n < 4000) <!> 这个检查引发了 testNegative 期待的 OutOfRangeError 异常。

JasonXie 同意


最后两段

  • You're down to 6 failures, and all of them involve fromRoman: the known values test, the three separate bad input tests, the case check, and the sanity check. That means that toRoman has passed all the tests it can pass by itself. (It's involved in the sanity check, but that also requires that fromRoman be written, which it isn't yet.) Which means that you must stop coding toRoman now. No tweaking, no twiddling, no extra checks “just in case”. Stop. Now. Back away from the keyboard.
  • 你已将失败降至6个,而且他们都是关于 fromRoman 的:已知值测试,三 <!> 种不同个独立的无效输入测试,大小写检查和 <!> 回旋完备性检查。这意味着 toRoman 通过了所有可以独立通过的测试( <!> 回旋完备性测试也测试它,但需要 fromRoman 编写后一起测试)。 这就是说,你应该停止对 toRoman 的代码编写。不必再推敲,不必再做额外的检查 “恰到好处”。 停下来吧! 现在,别再敲键盘了。

  • The most important thing that comprehensive unit testing can tell you is when to stop coding. When all the unit tests for a function pass, stop coding the function. When all the unit tests for an entire module pass, stop coding the module.
  • 全面的单元测试能够告诉你 <!> 的最重要的事情是什么时候停止编写代码。当一个函数的所有单元测试都通过了,停止编写这个函数。一旦一个完整模块的单元测试通过了,停止编写这个模块。

JasonXie 同意

1.3. 第14章第4节 roman.py, 第4阶段

http://www.woodpecker.org.cn/obp/diveintopython-zh-5.4/zh-cn/dist/htmlflat/diveintopython.html#roman.stage4

第1段第2句

  • Thanks to the rich data structure that maps individual Roman numerals to integer values, this is no more difficult than the toRoman function.
  • 感谢 <!> 那个<!>个罗马数字和对应整数关连的完美数据结构,这个工作不比 toRoman 函数复杂。

JasonXie 同意


Example 14.9. roman4.py

  • This file is available in py/roman/stage4/ in the examples directory.
  • 这个程序可以 <!>在例子目录下的 py/roman/stage4/ 的 examples 目录中 <!> 获得 找到

JasonXie 同意


Example 14.11. Output of romantest4.py against roman4.py

  • <!>romantest4.py 测试 roman4.py 的 <!> 输出 结果

JasonXie 同意


测试结果注释1

  • Two pieces of exciting news here. The first is that fromRoman works for good input, at least for all the known values you test.
  • 这儿有两个 <!> 令人激动的消息。 第一个是 fromRoman 对于所有有效输入运转正常,至少对于你测试的 已知值 是这样。

JasonXie 同意


测试结果注释2

  • The second is that the sanity check also passed. Combined with the known values tests, you can be reasonably sure that both toRoman and fromRoman work properly for all possible good values. (This is not guaranteed; it is theoretically possible that toRoman has a bug that produces the wrong Roman numeral for some particular set of inputs, and that fromRoman has a reciprocal bug that produces the same wrong integer values for exactly that set of Roman numerals that toRoman generated incorrectly. Depending on your application and your requirements, this possibility may bother you; if so, write more comprehensive test cases until it doesn't bother you.)
  • 第二个好消息是, <!> 回旋完备性测试也通过了。 与已知值测试的通过一起来看,你有理由相信 toRoman 和 fromRoman 对于所有有效输入值工作正常( <!> 这并不是完全肯定的还不能完全相信,理论上 <!>存在这种可能性, toRoman 存在错误而导致一些特定输入产生错误罗马数字表示 <!>恰巧 fromRoman 存在相应的错误,把特定) toRoman 错误产生的这些罗马数字错误地转换为最初的整数。 取决于你的应用程序和你的 <!>要求需求,你或许需要考虑这个可能性。如果是这样,编写更全面的 <!> 独立测试测试用例直到解决这个问题)。

JasonXie 这并不是完全肯定的改作尚不能完全确定,此处愿意是给出承诺,主动色彩较重。可能性后面应改作冒号,

1.4. 第14章第5节 roman.py, 第5阶段

http://www.woodpecker.org.cn/obp/diveintopython-zh-5.4/zh-cn/dist/htmlflat/diveintopython.html#roman.stage5

第1段

  • Now that fromRoman works properly with good input, it's time to fit in the last piece of the puzzle: making it work properly with bad input.That means finding a way to look at a string and determine if it's a valid Roman numeral. This is inherently more difficult than validating numeric input in toRoman, but you have a powerful tool at your disposal: regular expressions.
  • <!> 先在现在 fromRoman 对于有效输入能够正常工作 <!> ,是揭开最后一个谜底的时候了: <!> 无效输入的情形下的正常运转使它正常工作于无效输入的情况下。这意味着要找出一个方法 <!> 查看输入字符串并确定它检查一个字符串是不是一个有效的罗马数字。这比 toRoman 中 <!> 有效数字输入的查看验证有效的数字输入 困难, 但是你可以使用一个强大的工具:正则表达式。

JasonXie 可以


第3段

  • As you saw in Section 7.3, “Case Study: Roman Numerals”, there are several simple rules for constructing a Roman numeral, using the letters M, D, C, L, X, V, and I. Let's review the rules:
  • 如你在 第 7.3 节 “个案研究:罗马字母”中所见到的, <!> 有很多构建罗马数则的简单方法构建罗马数字有几个简单的规则:使用字母 M, D, C, L, X, V,和 I。让我们回顾一下这些规则

JasonXie 同意


罗马数字规则

  • 1. Characters are additive. I is 1, II is 2, and III is 3. VI is 6 (literally, “5 and 1”), VII is 7, and VIII is 8.
  • 1. 字符是 <!> 被堆放“加”在一起的: I 是 1, II 是 2, III 是 3。 VI 是 6 (看上去就是 5 <!>“加” 1), VII 是 7, VIII 是 8。

JasonXie 同意

  • 2. The tens characters (I, X, C, and M) can be repeated up to three times. At 4, you need to subtract from the next highest fives character. You can't represent 4 as IIII; instead, it is represented as IV (“1 less than 5”). 40 is written as XL (“10 less than 50”), 41 as XLI, 42 as XLII, 43 as XLIII, and then 44 as XLIV (“10 less than 50, then 1 less than 5”).
  • 2. <!> 这十个代表能够被10整除的数字的字符( I, X, C, 和 M) <!> 可以重复最多最多可以重复三次。 对于 4, <!> 你需要由接下来的五做减法你则需要利用下一个最大的能够被5整除的字符进行减操作得到。你不能把 4 表示为 IIII <!>,而是应该表示为 IV (“比 5 小 1 ”)。 40 则被写作 XL (“比 50 小 10”), 41 表示为 XLI, 42 表示为 XLII, 43 表示为 XLIII, 44 表示为 XLIV (“比50小10,又比 5 小 1”).

JasonXie 下一个最大的能够被5整除 的说法不妥。按照这样的讲法 40的下一个应该是45而不是50。我原来的翻译是直译过来的(毕竟原文也没说明白),一定希望翻译明白的话只能多说两句需要由下一个同一位上为5的数做减法 或者就简单地讲 4 需要从 5 做减法

  • 3. Similarly, at 9, you need to subtract from the next highest tens character: 8 is VIII, but 9 is IX (“1 less than 10”), not VIIII (since the I character can not be repeated four times). 90 is XC, 900 is CM.
  • <!> 如法炮制,9需要从十做减法而得:8 是 VIII,而 9 是 IX (“比 10 小 1”),而不是 VIIII (由于 I 不能重复四次)。 90 表示为 XC, 900 表示为 CM, 类似的,对于数字 9,你必须利用下一个能够被10整除的字符进行减操作得到: 8 表示为 VIII, 而 9 则表示为 IX (比10 小1), 而不是 VIIII (因为字符I 不能连续重复四次)。数字90 表示为 XC, 900 表示为 CM.

JasonXie 同上,整除的讲法不妥。这句建议维持原译。

  • 4. The fives characters can not be repeated. 10 is always represented as X, never as VV. 100 is always C, never LL.
  • <!> 有五个字符不能被重复: 10 应该表示为 X, 而不会是 VV。 100 应该表示为 C,而不是 LL. 被5整除的字符不能重复。数字10 常表示为X, 而从来不用VV来表示。数字100总表示为C, 从不表示为 LL.

JasonXie 同上,整除的讲法不可取

  • 5. Roman numerals are always written highest to lowest, and read left to right, so order of characters matters very much. DC is 600; CD is a completely different number (400, “100 less than 500”). CI is 101; IC is not even a valid Roman numeral (because you can't subtract 1 directly from 100; you would need to write it as XCIX, “10 less than 100, then 1 less than 10”).
  • <!> 罗马数字总是有大到小书写,从左到右读,所以字符的顺序很重要。 DC 是 600, CD 是完全另外一个数 (400,“比 500 少 100”)。 CI 是 101,而 IC 根本就不是一个有效的罗马数字(因为你无法从100直接减1应该写成 XCIX, “比 100 少 10,比 10 少 1”)。罗马数字经常从高位到低位书写,从左到右阅读,因此不同顺序的字符意义大不相同。DC 表示 600; 而CD 是一个完全不同的数字(为400, 也就是比500 小100). CI 表示 101; 而IC 甚至不是一个合法的罗马字母(因为你不能直接从数字100减去1; 比需要写成XCIX, 意思是 比100 小10, 然后加上数字9,也就是比 10小1的数字).

  • {i} 这里使用了第7章中的翻译

JasonXie 第7章的整除讲法不妥,建议统稿者考虑修改。


Example 14.12. roman5.py

  • This file is available in py/roman/stage3/ in the examples directory.
  • 这个程序可以 <!>在例子目录下的 py/roman/stage5/ 的 examples 目录中 <!> 获得 找到

JasonXie 同意


程序注释1

  • This is just a continuation of the pattern you discussed in Section 7.3, “Case Study: Roman Numerals”. The tens places is either XC (90), XL (40), or an optional L followed by 0 to 3 optional X characters. The ones place is either IX (9), IV (4), or an optional V followed by 0 to 3 optional I characters.
  • 这只是 第 7.3 节 “个案研究:罗马字母” 中讨论的匹配模版的继续。 十位 <!> 可能是XC (90), XL (40),或者是一个可能 <!> 有的 L <!> 后面跟着 0 到 3 个 X 字符。 个位则可能是 IX (9), IV (4),或者是一个可能 <!> 有的V后面跟着 0 到 3 个 I 字符。

JasonXie 同意


程序注释2

  • Having encoded all that logic into a regular expression, the code to check for invalid Roman numerals becomes trivial. If re.search returns an object, then the regular expression matched and the input is valid; otherwise, the input is invalid.
  • 把所有的逻辑 <!> 编码表示成正则表达式,检查无效罗马字符 <!> 便轻而易举了的代码就很简单了。 如果 re.search 返回一个对象则 <!> 正则表达式检查输入表示匹配了正则表达式<!> 匹配则输入是有效的,否则输入无效。

JasonXie 基本同意,但编码成是原意,改做表示成会不会有些语义损失?


Example 14.13. Output of romantest4.py against roman4.py

  • <!>romantest5.py 测试 roman5.py 的 <!> 输出 结果

JasonXie 同意


结果说明1

  • One thing I didn't mention about regular expressions is that, by default, they are case-sensitive. Since the regular expression romanNumeralPattern was expressed in uppercase characters, the re.search check will reject any input that isn't completely uppercase. So the uppercase input test passes.
  • <!> 有件事我未曾讲过,那就是默认情况下正则表达式大小写敏感。关于正则表达式有一点我没有提到,就是默认情况下正则表达式是大小写敏感的。 由于正则表达式 romanNumeralPattern 是以大写字母构造的,re.search 将拒绝不全部是大写字母构成的输入。 因此大写输入的检查 <!>通过了。

JasonXie 一句中出现两次正则表达式有些重复之感,况且原文只出现一次。


结果说明2

  • More importantly, the bad input tests pass. For instance, the malformed antecedents test checks cases like MCMC. As you've seen, this does not match the regular expression, so fromRoman raises an InvalidRomanNumeralError exception, which is what the malformed antecedents test case is looking for, so the test passes.

  • 更重要的是,无效输入测试 <!> 通过了。 例如, <!> 前面那个独立测试测试用例testMalformedAntecedent <!> 需要查看检查 MCMC 之类的情形。 正如你所见,这不 <!> 符合匹配正则表达式, 因此 fromRoman 引发一个 <!> 独立测试测试用例testMalformedAntecedent正在等待的 InvalidRomanNumeralError 异常,所以测试通过了。

JasonXie 同意


结果说明3

  • In fact, all the bad input tests pass. This regular expression catches everything you could think of when you made your test cases.
  • 事实上,所有的无效输入测试都通过 <!> 。 正则表达式捕捉了所有你在编写 <!> 独立测试测试用例时所能预见的所有情况。

JasonXie 同意


结果说明4

  • And the anticlimax award of the year goes to the word “OK”, which is printed by the unittest module when all the tests pass.
  • 一步步缩减错误个数最终迎来了 “OK”这个 <!> 平淡的“年度大奖”, <!> unittest 模块在所有测试都通过后打印出来的单词 所有测试都通过后 unittest 模块就会输出它

JasonXie 同意