Python 初學番外篇—如何測試自己的程式
利用檔案處理、線上開發環境或是 Command-Line 來測試自己的程式
在學習任何程式語言的過程中,都需要學習如何測試自己的程式,以得到正確的結果或是修改自己的程式來完成需求。但有時候只是想要對程式進行測試,卻發現測試資料太過冗長,一行一行輸入並不太方便,因此以下將在給定一個題目的情況下,試著提供幾個測試自己程式時可以利用的小技巧。
舉例來說,如果我們今天有一個題目,敘述如下:
cc 集團推出計程車服務 ccTAXI 服務,費用計算方式如下:p1 * 移動總距離 + p2 * 四個方向(東西南北)的單次最大移動距離加總 (詳細說明請見 hint)給定計費參數 p1、p2、乘客上車的位置,以及計程車行駛的路徑,請計算
1.下車的座標
2.該趟的車資輸入的第一行為計費參數(p1 p2)
輸入的第二行為初始位置(x y)
輸入的第三行開始為路徑,若為 "N" 在 y 軸方向增加,"E" 則在 x 軸方向增加,以此類推
輸入的最後一行為 "0",代表路程結束
意思就是我們會需要計算兩種不同費用的和,一個是總路程乘上費率1,另一個是東西南北四個方向單次最大移動距離的和乘上費率2,以及經過移動以後的座標位置。
範例測資:
那麼我們解題的思維可能像這樣:
1. 從測資得到兩種計費價格以及初始座標後,逐行去讀取單次的移動方向和移動距離。
2. 先確認是否要更新這個方向的最大移動距離(因為要計入第二個價格),在移動的總距離上加上這個量,然後利用一開始設定好的 nsew 來處理座標的更改以後,再讀取下一行測資,直到遇到輸入為 0 ,最後輸出最終座標以及價格。
打算測試的程式碼如下:
了解了這次要處理的問題,以及我們試寫的程式碼以後,接下來我們會介紹三種方式來測試這段程式碼,希望可以讓大家學會這些方法以後,更加熟練的測試自己的程式:
- 使用任意編輯器搭配檔案處理
- 利用線上開發環境執行所寫程式碼
- 透過 Command-line 簡化輸入/輸出流程
使用任意 Python 編輯器搭配檔案處理
在Python 初學第十二講 — 檔案處理當中,曾經提過當我們的程式要進行檔案處理時的方法。當然,要從檔案裡讀取的,不一定只是我們需要處理的資料,我們也可以將輸入複製貼上在檔案當中,以供程式讀取。
因此我們的測試方法可能會以如下的思路進行:我們先將測資複製貼上到一個文字檔案,並且存檔,然後再利用 file 的方法將這個文字檔逐行讀入,並利用每讀進檔案中的一行內容視為使用一次 input()
的方法來讀進我們的程式當中。
我們將測資複製貼上進文字檔案中,在此處我們選擇 txt
的檔案類型,但其他檔案類型,如 in
等也可以用以下的方法讀取。
而我們利用 file.readline()
取代 input()
的改編如下:
可以依據問題以及使用情況來自由選擇 file.readline()
或是 for line in file
的方法來模擬逐行讀取的動作,舉例來說,若我們需要大量處理相同或類似格式的輸入,通常會選擇後者;但若輸入的行數固定,前者也不失為一個選擇。
使用 Jupyter Notebook 執行上述程式碼的執行結果如下圖:
如果不使用 Jupyter Notebook 而是使用其他編輯器的情況底下,我們的程式碼通常都是儲存成一個 .py
檔案來執行的,如果不想在檔案中將測資檔案的位置寫死,又該怎麼做呢?此時我們要利用的是 Python 的內建模組 sys
。
sys
是 Python 內建的模組,通常用來取得系統的參數或是函式。而這次我們所要用的,就是 sys
當中的物件 argv
。 argv
用來取得從命令列傳入的參數,藉由這個參數,我們可以在執行 .py
時才給定檔案路徑,不需要一開始在程式碼當中寫死。使用的方法如下:
我們將如下的程式碼,利用任何編輯器(Python原生IDLE、sublime、Visual Studio Code、Spyder、PyCharm等等)儲存在一個 .py
檔中,並命名為 taxi.py
:
我們在原本放檔案路徑的位置上,放了 sys.argv[1]
這個參數。為什麼是 sys.argv[1]
呢?這就要提到這個程式碼的執行方式了。先來看看怎麼執行這個 .py
檔吧!通常利用命令列(terminal/cmd)執行 Python 程式碼的方法如下:
$python3 [path_to_code]
我們可以利用命令列來執行上述的指令,讓 python 來跑我們的 .py
程式碼。但是今天我們希望這個程式碼得到來自外面的輸入,故寫法如下:
$python3 [path_to_code] [path_to_file]
執行結果如下圖:
我們利用 Python3 來叫我們電腦裡的 Python 執行 taxi.py
這個程式碼,然後給定檔案路徑,利用 sys.argv
來將檔案路徑放進程式碼當中讀取檔案的位置。那麼回到剛剛的問題,為什麼是 sys.argv[1]
呢? sys.argv
是一個系統參數的串列,在上圖的範例裡,sys.argv[0]
指的是我們所給的程式碼 taxi.py
的路徑,而 sys.argv[1]
指的就是放在第二個參數,也就是檔案路徑。
至此我們完成了藉由檔案的輸入來測試程式的方法,藉由檔案處理的小技巧,可以模擬使用者的輸入,簡化手動輸入的流程來測試我們的程式,得到我們所要的輸出結果。跟讀取檔案相關的詳細做法可以參考Python 初學第十二講 — 檔案處理的內容。
利用線上開發環境執行所寫程式
當然,有很多事情不需要我們自己親力親為,網路上的線上資源相當多,如果我們沒有已經設定好的程式開發環境,在此我們也推薦一個線上的 IDE (整合開發環境),可以讓我們輕鬆地輸入較為大量的測資,並且執行我們所寫的 py 檔。
Repl.it: 一個支援多種程式語言的雲端開發環境,包含 Python、node.js、C、C++、Java、Go…等等,結合程式設計、專案開發以及教學用途,也是許多人如果一時之間沒有適當開發環境時的首選。介面長相如下:
當我們寫完程式以後,只需要按 run 就可以執行,並可以直接利用右側的命令列,直接貼上測資即可。
示範如下:
藍框處即為我們測試的結果輸出,在貼上測資以後按 enter
就會直接跑出結果,呈現在螢幕上。使用相當便捷,但若輸出較為複雜,或是需要另外將輸出儲存起來,就不是那麼適合。
透過 Command-Line 簡化輸入流程
最後要介紹的方法是利用上面提到的,利用命令列(Terminal/cmd)來執行程式碼的方法。剛才我們提到過,如果我們要用命令列執行一個程式碼,寫法如下:
$python3 [path_to_code]
然而,有一個十分簡單的方法可以讓我們將測試資料輸入進我們的程式,不需要將 input()
改成任何東西,只需要使用最原本的 code :
我們將上面的 code 存進 taxi_simple.py
這個程式碼檔案當中,並且使用剛才的 testcase.txt
。接著,我們命令列要輸入的指令如下:
$python3 [path_to_code] < [path_to_file]
執行結果如下:
由上圖可見,我們使用了一個小於符號 <
,這個符號是用來打開符號後面的檔案(也就是我們的 testcase.txt
),並且程式的標準輸入從來自命令列(鍵盤輸入)改成該檔案的內容,讓程式碼讀進去的方法。利用這個簡單的小符號,就可以幫助我們完成複雜的測資輸入流程,是不是很方便呢?
到這裡為止我們分享了幾種不同的輸入測資方式,但有時我們不只需要面對冗長的輸入,還需要處理同樣冗長的輸出,光是比對輸出是否正確都經常需要花上許多時間,因此我們也來分享幾個實用的小技巧,接下來要補充如何得到輸出的結果,並存成檔案,以及如何比對是否正確。
如何儲存測試結果?
當然,我們可以透過檔案處理的輸出方式來儲存我們的測試結果,利用 file.write()
或是 print()
時透過指定參數 file
的方式來寫入檔案,詳細的方法可以參見Python 初學第十二講 — 檔案處理。總而言之,我們結合剛才所提到的 sys.argv
,改寫程式碼如下並儲存為 taxi_out.py
這個檔案:
而此時的用法則如下:
$python3 [path_to_code] [path_to_input_file] [path_to_output_file]
結合程式碼很明顯可以看出,我們將 sys.argv[1]
作為測試輸入的檔案路徑讀進程式碼,進行運算以後,再輸出至 sys.argv[2]
所給的檔案路徑。測試結果如下:
可以看出,我們所跑出的結果都儲存進了 out.txt
這個檔案當中。
那麼,有沒有跟剛才使用 <
一樣簡單的方法呢?當然有,就是使用 >
這個符號。同樣使用最一開始的程式碼 simple_taxi.py
:
接著使用如下的方法:
$python3 [path_to_code] <[path_to_input_file] >[path_to_output_file]
相對於剛才 <
的定義,在此使用 >
則是代表我們將原本要輸出在命令列當中的輸出,改成輸出到指定的檔案當中,執行結果就會被儲存在我們所指定的檔案當中。執行結果如下圖:
上述兩種方法都可以將我們的輸出存成檔案,以供後續使用。
如何比對輸出結果?
當輸出結果太過冗長,光是要比對都要花上許多時間和精力。儲存成檔案的好處就是,可以不必用肉眼來比對自己的結果以及正確答案,而是可以透過命令列的指令來完成這個工作,在此分享在不同作業系統(Windows, Mac OS, Linux, Unix)下的解法。
如果使用的是 mac 以及 Linux、Unix,用法如下:
$diff [file_1] [file_2]
可以直接比對兩個檔案的內容,如果有不同的地方,將會告訴我們在哪個位置有差異。舉例來說,如果我們有兩個檔案內容如下:
兩者的差異只在於第二行的最後一位數字,此時若我們使用 diff
命令,可以得到執行結果如下:
從輸出的結果可以看出這兩個檔案不同之處,若兩個檔案內容一模一樣,將不會輸出任何東西。
至於 Windows 作業系統下的比較,可以使用 FC
這個命令,也可以安裝 WinMerge
等等用於檔案、程式碼比較的軟體,就可以輕鬆的完成比較結果的過程,並且據此修改程式碼,以完成我們的工作或是專案。
學會如何善用命令列或是小工具來完善我們的程式碼,有助於我們進行程式設計的學習以及進步,也可以簡化我們許多不必要的時間成本,朝著成為更好的程式設計者之路邁進。
我們是 ccClub 團隊,致力於讓 Python 成為大家的第二外語,希望能用淺顯易懂、循序漸進的方式,帶領新手一步步跨入程式設計的世界。
如果你喜歡這篇文章,請給我們 1~10 個掌聲。
如果你喜歡「Python初學」的教學系列文,請給我們 11 個以上的掌聲。
Facebook: ccClub Python讀書會