<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            15.4. 后記

            聰明的讀者在學習前一節時想得會更深入一層。現在寫的這個程序中最令人頭痛的性能負擔是正則表達式,但它是必需的,因為沒有其它方法來識別羅馬數字。但是,它們只有 5000 個,為什么不一次性地構建一個查詢表來讀取?不必用正則表達式凸現了這個主意的好處。你建立了整數到羅馬數字查詢表的時候,羅馬數字到整數的逆向查詢表也構建了。

            更大的好處在于,你已經擁有一整套完全的單元測試。你修改了多半的代碼,但單元測試還是一樣的,因此你可以確定你的新代碼與來的代碼一樣可以正常工作。

            例 15.17. roman9.py

            這個文件可以在例子目錄下的 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()
            

            這樣有多快呢?

            例 15.18. 用 romantest9.py 測試 roman9.py 的結果

            
            .............
            ----------------------------------------------------------------------
            Ran 13 tests in 0.791s
            
            OK
            
            

            還記得嗎?你原有版本的最快速度是 13 個測試耗時 3.315 秒。當然,這樣的比較不完全公平,因為這個新版本需要更長的時間來導入 (當它填充查詢表時)。但是導入只需一次,在運行過程中可以忽略。

            這個重構的故事的寓意是什么?

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线