用 Linkbot 學習 Python 3 / 除錯
- "在我們開始程式設計後,我們驚訝地發現,編寫正確的程式並不像我們想象的那麼容易。除錯必須被發現。我還記得那一刻,我意識到我餘生中很大一部分時間將花費在我自己程式的錯誤尋找上。"— 莫里斯·威爾克斯發現除錯,1949 年
到目前為止,如果你一直在玩弄你的程式,你可能已經發現,有時程式會做一些你不想它做的事情。這是相當常見的。除錯是找出計算機在做什麼,然後讓它做你想讓它做的事情的過程。這可能很棘手。令人驚訝的是,花費數週時間追蹤和修復一個由某人將 x 放在應該放置 y 的地方而導致的 bug 非常常見。
本章將比之前的章節更抽象。
第一步(這聽起來很明顯)是弄清楚程式如果正確執行應該在做什麼。想出一些測試用例,看看會發生什麼。
例如,讓我們嘗試編寫一個程式,該程式讓一個帶有兩個輪子的 Linkbot-I 前進旋轉一圈,同時使 LED 變為綠色,然後讓 Linkbot 向後滾動,LED 變為紅色。以下是該程式的第一個嘗試
import barobo
dongle = barobo.Dongle()
dongle.connect()
myLinkbot = dongle.getLinkbot('ABCD') # Change 'ABCD' to your Linkbot's Serial ID
myLinkbot.moveNB(360, 0, -360) # Roll Forward
myLinkbot.setLEDColor(0, 255, 0) # Set LED to green
myLinkbot.moveNB(-360, 0, 360) # Roll Backward
myLinkbot.setLEDColor(255, 0, 0) # Set the LED color to red
乍一看,上面的程式似乎是正確的。但是,當您實際嘗試它時,您會發現機器人永遠不會將 LED 變成綠色,而且它永遠不會向前移動。它會立即將 LED 變為紅色並向後移動。發生在應該讓機器人向前滾動並使 LED 變為綠色的兩行程式碼上的事情是什麼?
除錯此類問題的一種簡單而有效的方法是使用 print() 函式在程式執行時跟蹤其進度。讓我們嘗試將一些 print 語句新增到我們的原始程式中,看看是否可以找到問題
import barobo
dongle = barobo.Dongle()
dongle.connect()
myLinkbot = dongle.getLinkbot('ABCD') # Change 'ABCD' to your Linkbot's Serial ID
print("Moving forward...")
myLinkbot.moveNB(360, 0, -360) # Roll Forward
print("Done. Setting LED to green...")
myLinkbot.setLEDColor(0, 255, 0) # Set LED to green
print("Done. Moving backward...")
myLinkbot.moveNB(-360, 0, 360) # Roll Backward
print("Done. Setting LED to red...")
myLinkbot.setLEDColor(255, 0, 0) # Set the LED color to red
print("Done.")
當您執行此程式時,請注意它列印的內容,以及它列印的方式和時間。當您執行程式時,您應該得到的輸出是
Moving forward... Done. Setting LED to green... Done. Moving backward... Done. Setting LED to red... Done.
但是,您會注意到所有這些語句都立即打印出來;在告訴機器人向前移動的命令和告訴它向後移動的命令之間沒有延遲。這應該立即給我們一個關於錯誤的指示:程式應該等到機器人完成向前移動後才向後移動並變為紅色。您會注意到,我們在程式中使用了非阻塞移動函式,以便我們可以同時移動和更改 LED 顏色。但是,我們也知道 Python 不會停止並等待非阻塞和“設定”函式。從上一章中,我們還有一個使 Python 等待非阻塞運動完成的函式,名為 moveWait()。讓我們嘗試修復我們損壞的程式
import barobo
dongle = barobo.Dongle()
dongle.connect()
myLinkbot = dongle.getLinkbot('ABCD') # Change 'ABCD' to your Linkbot's Serial ID
myLinkbot.moveNB(360, 0, -360) # Roll Forward
myLinkbot.setLEDColor(0, 255, 0) # Set LED to green
myLinkbot.moveWait() # Wait until the robot is finished rolling forward
myLinkbot.moveNB(-360, 0, 360) # Roll Backward
myLinkbot.setLEDColor(255, 0, 0) # Set the LED color to red
在兩個步驟之間添加了一個 moveWait() 語句。這迫使 Python 等待機器人完成向前移動後,才告訴它向後移動並將 LED 顏色設定為紅色。
如果沒有 moveWait() 語句,Python 會非常快地執行所有這些語句,以至於機器人向前滾動和綠色 LED 對人眼和耳朵來說是不可察覺的。只有最後一條命令,向後滾動和紅色 LED,會“停留在”機器人上,並且可以觀察到,這使得它看起來像 Python 完全跳過了向前滾動和綠色 LED。
- 這可能聽起來很明顯,但首先要確保的是您知道程式應該做什麼。
- 使用
print()語句檢查以確保程式流程是正確的。 - 使用
print()語句檢查以確保變數值是正確的。 - 對於可能使用迴圈和變數的複雜程式,嘗試逐行“逐步”執行程式,使用筆和紙跟蹤變數值和程式輸出。
- 如果您有一個很長的程式,它對一個變數執行許多計算,並且該變數的值在程式結束時是錯誤的,嘗試使用“二分查詢”方法來查詢 bug:使用
print()語句來檢查程式中間變數的值。如果值是正確的,則您知道 bug 位於程式的後半部分。在程式後半部分的中間放置另一個print()語句並檢查其值。重複此過程,直到找到錯誤地設定變數值的錯誤程式碼行。這種技術對於找到 bug 發生的位置非常有用,並且對於許多型別的 bug 都很有用。