| 導航:起始頁 > Dive Into Python > 函數編程 > 全部放在一起 | << >> | ||||
深入 Python :Dive Into Python 中文版Python 從新手到專家 [Dip_5.4b_CPyUG_Release] |
|||||
你已經學習了足夠的知識,現在來分析本章樣例代碼的前七行:讀取一個目錄并從中導入選定的模塊。
def regressionTest(): path = os.path.abspath(os.path.dirname(sys.argv[0])) files = os.listdir(path) test = re.compile("test\.py$", re.IGNORECASE) files = filter(test.search, files) filenameToModuleName = lambda f: os.path.splitext(f)[0] moduleNames = map(filenameToModuleName, files) modules = map(__import__, moduleNames) load = unittest.defaultTestLoader.loadTestsFromModule return unittest.TestSuite(map(load, modules))
讓我們一行行交互地看。假定當前目錄是 c:\diveintopython\py,其中有包含本章腳本在內的本書眾多樣例。正如在 第 16.2 節 “找到路徑” 中所見,腳本目錄將存于 path 變量,因此讓我們從這里開始以實打實的代碼起步。
>>> import sys, os, re, unittest >>> path = r'c:\diveintopython\py' >>> files = os.listdir(path) >>> files['BaseHTMLProcessor.py', 'LICENSE.txt', 'apihelper.py', 'apihelpertest.py', 'argecho.py', 'autosize.py', 'builddialectexamples.py', 'dialect.py', 'fileinfo.py', 'fullpath.py', 'kgptest.py', 'makerealworddoc.py', 'odbchelper.py', 'odbchelpertest.py', 'parsephone.py', 'piglatin.py', 'plural.py', 'pluraltest.py', 'pyfontify.py', 'regression.py', 'roman.py', 'romantest.py', 'uncurly.py', 'unicode2koi8r.py', 'urllister.py', 'kgp', 'plural', 'roman', 'colorize.py']
>>> test = re.compile("test\.py$", re.IGNORECASE)>>> files = filter(test.search, files)
>>> files
['apihelpertest.py', 'kgptest.py', 'odbchelpertest.py', 'pluraltest.py', 'romantest.py']
>>> filenameToModuleName = lambda f: os.path.splitext(f)[0]>>> filenameToModuleName('romantest.py')
'romantest' >>> filenameToModuleName('odchelpertest.py') 'odbchelpertest' >>> moduleNames = map(filenameToModuleName, files)
>>> moduleNames
['apihelpertest', 'kgptest', 'odbchelpertest', 'pluraltest', 'romantest']
| 正如你在 第 4.7 節 “使用 lambda 函數” 中所見,lambda 快餐式地創建內聯單行函數。這里應用你在 例 6.17 “分割路徑名” 中已經見過的,標準庫的 os.path.splitext 將一個帶有擴展名的文件名返回成只包含文件名稱的那部分。 | |
| filenameToModuleName 是一個函數。lambda 函數并不比你以 def 語句定義的普通函數神奇。你可以如其他函數一樣地調用 filenameToModuleName,它也將如你所愿:從參數中剔除擴展名。 | |
| 現在你可以通過 map 把這個函數應用于單元測試文件列表中的每一個文件。 | |
| 結果當然如你所愿:以指代模塊的字符串構成的一個列表。 |
>>> modules = map(__import__, moduleNames)>>> modules
[<module 'apihelpertest' from 'apihelpertest.py'>, <module 'kgptest' from 'kgptest.py'>, <module 'odbchelpertest' from 'odbchelpertest.py'>, <module 'pluraltest' from 'pluraltest.py'>, <module 'romantest' from 'romantest.py'>] >>> modules[-1]
<module 'romantest' from 'romantest.py'>
| 正如你在 第 16.6 節 “動態導入模塊” 中所見,你可以通過 map 和 __import__ 的協同工作,將模塊名 (字符串) 映射到實際的模塊 (像其他模塊一樣可以被調用和使用)。 | |
| modules 現在是一個模塊列表,其中的模塊和其他模塊一樣。 | |
| 該列表的最后一個模塊是 romantest 模塊,和通過 import romantest 導入的模塊完全等價。 |
>>> load = unittest.defaultTestLoader.loadTestsFromModule >>> map(load, modules)[<unittest.TestSuite tests=[ <unittest.TestSuite tests=[<apihelpertest.BadInput testMethod=testNoObject>]>, <unittest.TestSuite tests=[<apihelpertest.KnownValues testMethod=testApiHelper>]>, <unittest.TestSuite tests=[ <apihelpertest.ParamChecks testMethod=testCollapse>, <apihelpertest.ParamChecks testMethod=testSpacing>]>, ... ] ] >>> unittest.TestSuite(map(load, modules))
![]()
自省過程是 unittest 模塊經常為我們做的一項工作。還記得我們的獨立測試模塊僅僅調用了看似神奇的 unittest.main() 函數就大刀闊斧地完成了全部工作嗎?unittest.main() 實際上創建了一個 unittest.TestProgram 的實例,而這個實例實際上創建了一個 unittest.defaultTestLoader 的實例并以調用它的模塊啟動它。 (如果你不給出,如何知道調用它的模塊是哪一個?通過使用同樣神奇的 __import__('__main__') 命令,動態導入正在運行的模塊。我可以就 unittest 模塊中使用的所有技巧和技術寫一本書,但那樣我就沒法寫完這本了。)
<< 動態導入模塊 |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
小結 >> |