| 導航:起始頁 > Dive Into Python > 重構 > 重構 | << >> | ||||
深入 Python :Dive Into Python 中文版Python 從新手到專家 [Dip_5.4b_CPyUG_Release] |
|||||
全面的單元測試帶來的最大好處不是你的全部測試用例最終通過時的成就感;也不是被責怪破壞了別人的代碼時能夠證明 自己的自信。最大的好處是單元測試給了你自由去無情地重構。
重構是在可運行代碼的基礎上使之工作得更好的過程。通常,“更好”意味著“更快”,也可能意味著 “使用更少的內存”,或者 “使用更少的磁盤空間”,或者僅僅是“更優雅的代碼”。不管對你,對你的項目意味什么,在你的環境中,重構對任何程序的長期良性運轉都是重要的。
這里,“更好” 意味著 “更快”。更具體地說,fromRoman 函數可以更快,關鍵在于那個丑陋的、用于驗證羅馬數字有效性的正則表達式。嘗試不用正則表達式去解決是不值得的 (這樣做很難,而且可能也快不了多少),但可以通過預編譯正則表達式使函數提速。
>>> import re >>> pattern = '^M?M?M?$' >>> re.search(pattern, 'M')<SRE_Match object at 01090490> >>> compiledPattern = re.compile(pattern)
>>> compiledPattern <SRE_Pattern object at 00F06E28> >>> dir(compiledPattern)
['findall', 'match', 'scanner', 'search', 'split', 'sub', 'subn'] >>> compiledPattern.search('M')
<SRE_Match object at 01104928>
| 在需要多次使用同一個正則表達式的情況下,應該將它進行編譯以獲得一個 pattern 對象,然后直接調用這個 pattern 對象的方法。 | |
這個文件可以在例子目錄下的 py/roman/stage8/ 目錄中找到。
如果您還沒有下載本書附帶的樣例程序, 可以 下載本程序和其他樣例程序。
# toRoman and rest of module omitted for clarity romanNumeralPattern = \ re.compile('^M?M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$')def fromRoman(s): """convert Roman numeral to integer""" if not s: raise InvalidRomanNumeralError, 'Input can not be blank' if not romanNumeralPattern.search(s):
raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s result = 0 index = 0 for numeral, integer in romanNumeralMap: while s[index:index+len(numeral)] == numeral: result += integer index += len(numeral) return result
那么編譯正則表達式可以提速多少呢?你自己來看吧:
.............---------------------------------------------------------------------- Ran 13 tests in 3.385s
OK
我還想做另外一個性能優化工作。就正則表達式語法的復雜性而言,通常有不止一種方法來構造相同的表達式是不會令人驚訝的。在 comp.lang.python 上對該模塊進行一些討論后,有人建議我使用 {m,n} 語法來查找可選重復字符。
這個文件可以在例子目錄下的 py/roman/stage8/ 目錄中找到。
如果您還沒有下載本書附帶的樣例程序, 可以 下載本程序和其他樣例程序。
# rest of program omitted for clarity #old version #romanNumeralPattern = \ # re.compile('^M?M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$') #new version romanNumeralPattern = \ re.compile('^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$')![]()
這樣的正則表達簡短一些 (雖然可讀性不太好)。核心問題是,是否能加快速度?
............. ---------------------------------------------------------------------- Ran 13 tests in 3.315sOK
還有另外一個我想做的調整,我保證這是最后一個,之后我會停下來,讓這個模塊歇歇。就像你多次看到的,正則表達式越晦澀難懂越快,我可不想在六個月內再回頭試圖維護它。是呀!測試用例通過了,我便知道它工作正常,但如果我搞不懂它是如何 工作的,添加新功能、修正新 Bug,或者維護它都將變得很困難。正如你在 第 7.5 節 “松散正則表達式” 看到的,Python 提供了逐行注釋你的邏輯的方法。
該文件可以在例子目錄下的 py/roman/stage8/ 目錄中找到。
如果您還沒有下載本書附帶的樣例程序, 可以 下載本程序和其他樣例程序。
# rest of program omitted for clarity #old version #romanNumeralPattern = \ # re.compile('^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$') #new version romanNumeralPattern = re.compile(''' ^ # beginning of string M{0,4} # thousands - 0 to 4 M's (CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's), # or 500-800 (D, followed by 0 to 3 C's) (XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's), # or 50-80 (L, followed by 0 to 3 X's) (IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's), # or 5-8 (V, followed by 0 to 3 I's) $ # end of string ''', re.VERBOSE)![]()
<< 應對需求變化 |
| 1 | 2 | 3 | 4 | 5 | |
后記 >> |