Python已經演化出了一個廣泛的生態系統,該生態系統能夠讓Python程序員的生活變得更加簡單,減少他們重復造輪的工作。同樣的理念也適用於工具開發者的工作,即便他們開發出的工具並沒有出現在最終的程序中。本文將介紹Python程序員必知必會的開發者工具。
對於開發者來說,最實用的幫助莫過於幫助他們編寫代碼文檔了。pydoc模塊可以根據源代碼中的docstrings為任何可導入模塊生成格式良好的文檔。Python包含了兩個測試框架來自動測試代碼以及驗證代碼的正確性:1)doctest模塊,該模塊可以從源代碼或獨立文件的例子中抽取出測試用例。2)unittest模塊,該模塊是一個全功能的自動化測試框架,該框架提供了對測試准備(test fixtures), 預定義測試集(predefined test suite)以及測試發現(test discovery)的支持。
trace模塊可以監控Python執行程序的方式,同時生成一個報表來顯示程序的每一行執行的次數。這些信息可以用來發現未被自動化測試集所覆蓋的程序執行路徑,也可以用來研究程序調用圖,進而發現模塊之間的依賴關系。編寫並執行測試可以發現絕大多數程序中的問題,Python使得debug工作變得更加簡單,這是因為在大部分情況下,Python都能夠將未被處理的錯誤打印到控制台中,我們稱這些錯誤信息為traceback。如果程序不是在文本控制台中運行的,traceback也能夠將錯誤信息輸出到日志文件或是消息對話框中。當標准的traceback無法提供足夠的信息時,可以使用cgitb 模塊來查看各級棧和源代碼上下文中的詳細信息,比如局部變量。cgitb模塊還能夠將這些跟蹤信息以HTML的形式輸出,用來報告web應用中的錯誤。
一旦發現了問題出在哪裡後,就需要使用到交互式調試器進入到代碼中進行調試工作了,pdb模塊能夠很好地勝任這項工作。該模塊可以顯示出程序在錯誤產生時的執行路徑,同時可以動態地調整對象和代碼進行調試。當程序通過測試並調試後,下一步就是要將注意力放到性能上了。開發者可以使用profile以及timit模塊來測試程序的速度,找出程序中到底是哪裡很慢,進而對這部分代碼獨立出來進行調優的工作。Python程序是通過解釋器執行的,解釋器的輸入是原有程序的字節碼編譯版本。這個字節碼編譯版本可以在程序執行時動態地生成,也可以在程序打包的時候就生成。compileall模塊可以處理程序打包的事宜,它暴露出了打包相關的接口,該接口能夠被安裝程序和打包工具用來生成包含模塊字節碼的文件。同時,在開發環境中,compileall模塊也可以用來驗證源文件是否包含了語法錯誤。
在源代碼級別,pyclbr模塊提供了一個類查看器,方便文本編輯器或是其他程序對Python程序中有意思的字符進行掃描,比如函數或者是類。在提供了類查看器以後,就無需引入代碼,這樣就避免了潛在的副作用影響。
如果函數,類或者是模塊的第一行是一個字符串,那麼這個字符串就是一個文檔字符串。可以認為包含文檔字符串是一個良好的編程習慣,這是因為這些字符串可以給Python程序開發工具提供一些信息。比如,help()命令能夠檢測文檔字符串,Python相關的IDE也能夠進行檢測文檔字符串的工作。由於程序員傾向於在交互式shell中查看文檔字符串,所以最好將這些字符串寫的簡短一些。例如
# mult.py
class Test:
"""
>>> a=Test(5)
>>> a.multiply_by_2()
10
"""
def __init__(self, number):
self._number=number
def multiply_by_2(self):
return self._number*2
在編寫文檔時,一個常見的問題就是如何保持文檔和實際代碼的同步。例如,程序員也許會修改函數的實現,但是卻忘記了更新文檔。針對這個問題,我們可以使用doctest模塊。doctest模塊收集文檔字符串,並對它們進行掃描,然後將它們作為測試進行執行。為了使用doctest模塊,我們通常會新建一個用於測試的獨立的模塊。例如,如果前面的例子Test class包含在文件mult.py中,那麼,你應該新建一個testmult.py文件用來測試,如下所示:
# testmult.py
import mult, doctest
doctest.testmod(mult, verbose=True)
# Trying:
# a=Test(5)
# Expecting nothing
# ok
# Trying:
# a.multiply_by_2()
# Expecting:
# 10
# ok
# 3 items had no tests:
# mult
# mult.Test.__init__
# mult.Test.multiply_by_2
# 1 items passed all tests:
# 2 tests in mult.Test
# 2 tests in 4 items.
# 2 passed and 0 failed.
# Test passed.
在這段代碼中,doctest.testmod(module)會執行特定模塊的測試,並且返回測試失敗的個數以及測試的總數目。如果所有的測試都通過了,那麼不會產生任何輸出。否則的話,你將會看到一個失敗報告,用來顯示期望值和實際值之間的差別。如果你想看到測試的詳細輸出,你可以使用testmod(module, verbose=True).
如果不想新建一個單獨的測試文件的話,那麼另一種選擇就是在文件末尾包含相應的測試代碼:
if __name__ == '__main__':
import doctest
doctest.testmod()
如果想執行這類測試的話,我們可以通過-m選項調用doctest模塊。通常來講,當執行測試的時候沒有任何的輸出。如果想查看詳細信息的話,可以加上-v選項。
$ python -m doctest -v mult.py