您当前位置:首页 > 深入 Python > 重构 > 后记 | << >> | ||||
深入 Python从 Python 新手到专家 |
一位聪明的读者阅读了上一节并将其提升到了一个新的水平。当前程序中最大的问题(也是性能瓶颈)是正则表达式,这是必需的,因为您没有其他方法来分解罗马数字。但它们只有 5000 个;为什么不构建一个查找表,然后直接读取呢?当您意识到根本不需要使用正则表达式时,这个想法就更好了。在构建用于将整数转换为罗马数字的查找表时,您可以构建反向查找表以将罗马数字转换为整数。
最棒的是,他已经有一套完整的单元测试。他更改了模块中一半以上的代码,但单元测试保持不变,因此他可以证明他的代码与原始代码一样有效。
此文件位于示例目录的 py/roman/stage9/ 中。
如果您还没有这样做,您可以下载本书中使用的此示例和其他示例。
#Define exceptions class RomanError(Exception): pass class OutOfRangeError(RomanError): pass class NotIntegerError(RomanError): pass class InvalidRomanNumeralError(RomanError): pass #Roman numerals must be less than 5000 MAX_ROMAN_NUMERAL = 4999 #Define digit mapping romanNumeralMap = (('M', 1000), ('CM', 900), ('D', 500), ('CD', 400), ('C', 100), ('XC', 90), ('L', 50), ('XL', 40), ('X', 10), ('IX', 9), ('V', 5), ('IV', 4), ('I', 1)) #Create tables for fast conversion of roman numerals. #See fillLookupTables() below. toRomanTable = [ None ] # Skip an index since Roman numerals have no zero fromRomanTable = {} def toRoman(n): """convert integer to Roman numeral""" if not (0 < n <= MAX_ROMAN_NUMERAL): raise OutOfRangeError, "number out of range (must be 1..%s)" % MAX_ROMAN_NUMERAL if int(n) <> n: raise NotIntegerError, "non-integers can not be converted" return toRomanTable[n] def fromRoman(s): """convert Roman numeral to integer""" if not s: raise InvalidRomanNumeralError, "Input can not be blank" if not fromRomanTable.has_key(s): raise InvalidRomanNumeralError, "Invalid Roman numeral: %s" % s return fromRomanTable[s] def toRomanDynamic(n): """convert integer to Roman numeral using dynamic programming""" result = "" for numeral, integer in romanNumeralMap: if n >= integer: result = numeral n -= integer break if n > 0: result += toRomanTable[n] return result def fillLookupTables(): """compute all the possible roman numerals""" #Save the values in two global tables to convert to and from integers. for integer in range(1, MAX_ROMAN_NUMERAL + 1): romanNumber = toRomanDynamic(integer) toRomanTable.append(romanNumber) fromRomanTable[romanNumber] = integer fillLookupTables()
那么它有多快?
.............
----------------------------------------------------------------------
Ran 13 tests in 0.791s
OK
请记住,您在原始版本中获得的最佳性能是在 3.315 秒内完成 13 次测试。当然,这不是完全公平的比较,因为此版本导入所需的时间更长(当它填充查找表时)。但由于导入只进行一次,因此从长远来看,这可以忽略不计。
这个故事的寓意是什么?
<< 重构 |
| 1 | 2 | 3 | 4 | 5 | |
总结 >> |