一切内容都是摘抄,主要是便于回忆和鼓励自己不要间断,更详细内容请见原帖地址:
《深入 python3 》中文版
http://woodpecker.org.cn/diveintopython3/index.html
10.1. 深入
在本书中还尚未提到该内容,因此现在让我们讲讲 字符串格式化 最后一点内容。从 Python 3.1 起,在格式化标示符中使用位置索引时可以忽略数字。也就是说,无需使用格式化标示符 {0} 来指向 format() 方法的第一个参数,只需简单地使用 {} 而 Python 将会填入正确的位置索引。该规则适用于任何数量的参数;第一个 {} 代表 {0},第二个 {} 代表 {1},以此类推。
用此方式编写代码将使得错误修正变得更困难。简单的错误(像这个)需要简单的测试实例;复杂的错误将会需要复杂的测试实例。在以测试为中心的环境中,由于必须在代码中精确地描述错误(编写测试实例),然后修正错误本身,看起来 好像 修正错误需要更多的时间。而如果测试实例无法正确地通过,则又需要找出到底是修正方案有错误,还数测试实例本身就有错误。然而从长远看,这种在测试代码和经测试代码之间的来回折腾是值得的,因为这样才更有可能在第一时间修正错误。同时,由于可以对新代码轻松地重新运行 所有 测试实例,在修正新代码时破坏旧代码的机会更低。今天的单元测试就是明天的回归测试。
10.2. 控制需求变化
10.3. 重构
让我们打断一下,进行一些剖析工作。可以说,最重要的是最后一行:
build_lookup_tables()
可以注意到这是一次函数调用,但没有 if
语句包裹住它。这不是 if __name__ == '__main__'
语块;模块被导入时 它将会被调用。(重要的是必须明白:模块将只被导入一次,随后被缓存了。如果导入一个已导入模块,将不会导致任何事情发生。因此这段代码将只在第一此导入时运行。)
这是一段聪明的程序代码……也许过于聪明了。上面定义了 to_roman() 函数;它在查询表中查找值并返回结果。而 build_lookup_tables() 函数重定义了 to_roman() 函数用于实际操作(像添加查询表之前的例子一样)。在 build_lookup_tables() 函数内部,对 to_roman() 的调用将会针对该重定义的版本。一旦 build_lookup_tables() 函数退出,重定义的版本将会消失 — 它的定义只在 build_lookup_tables() 函数的作用域内生效。
它不仅能够回答你的问题,还运行得非常快!好象速度提升了 10 倍。当然,这种比较并不公平,因为此版本在导入时耗时更长(在建造查询表时)。但由于只进行一次导入,启动的成本可以由对 to_roman() 和 from_roman() 函数的所有调用摊薄。由于该测试进行几千次函数调用(来回单独测试上万次),节省出来的效率成本得以迅速提升!
这个故事的寓意是什么?
- 简单是一种美德。
- 特别在涉及到正则表达式的时候。
- 单元测试令你在进行大规模重构时充满自信。