1. 程式人生 > 實用技巧 >使用PDB除錯Python程式

使用PDB除錯Python程式

使用PDB除錯Python程式

學習程式設計,除錯是寫過1000行程式碼後必須掌握的技能,很多同學因為不會除錯程式或者沒有除錯過問題,技能就停止不前了。

學習程式設計時,我提倡在Linux下使用命令列編譯,執行,除錯程式。學習C語言要掌握GDB,學習Java要掌握JDB,本文是《使用JDB除錯Java程式》的Python版本。我在課堂上講解過使用VSCode除錯程式,這是命令列版本。

Python程式中有邏輯錯誤,就需要使用Pdb來除錯了。除錯程式在IDE中很方便,但是我們在Linux環境下學習Python,那就需要在命令列下使用Pdb進行除錯了。

Pdb不但是個好的除錯工具,也是一個好的學習工具,可以讓你瞭解程式的動態執行過程。

學習建議:Linux Bash下開啟三個標籤頁

我們提倡在Linux命令列下學習Python程式設計。學習時在Ubuntu Bash中通過Ctrl+Alt+TCtrl+Shift+T快捷鍵開啟三個標籤(tab):一個使用vim編輯程式碼;一個使用python3編譯執行程式碼;一個使用PDB除錯程式碼。

如下圖所示,這樣就不用在一個視窗中進行編輯、編譯執行和除錯的切換了,能提高效率。

如上圖, 我們在Linux Bash中輸入 vim HelloPDB.py編輯除錯示例程式碼:

def main():
    i = 5
    j = 6
    sum = add(i, j)
    print(sum)

    sum = 0
    for i in range(0,101):
        sum = sum + i

    print(sum)

def add(augend, addend):
    sum = augend +addend
    return sum

if __name__ == '__main__':
    main()

程式碼編輯完,我們按 “:w” 進行儲存而不是 “:wq” 進行儲存退出,這樣在編譯或除錯中遇到問題就可以按Alt+1 進入第一個標籤修程式碼了。

我們按Alt+2 進入第二個標籤,使用python3 HelloPDB.py編譯執行程式。

我們按Alt+3 進入第三個標籤,使用python3 -m pdb HelloPDB.py對程式進行除錯。

除錯基礎

除錯程式先要學會設定斷點,這樣才能讓程式停在你感覺有問題的程式碼處進行排查。學習除錯我們要學會設定四種斷點:

  • 行斷點
  • 函式斷點
  • 條件斷點
  • 臨時斷點

我們在PDB中輸入 hhelp 可以檢視命令列表:

上圖中的bbreaktbreak

condition命令是與設定斷點相關的四個常用命令,其中bbreak的縮寫,可以相互替代。

-> def main():表示Pdb定位了到下一步要執行的程式碼def main()

我們通過執行b main命令在main函式開始處設定斷點:

如上圖,我們輸入r命令執行程式,程式會在main函式的第一行i=5處停下。

可以使用step命令執行main函式下一步程式碼i=5,使用ppp命令檢視變數i的值。

此時,由於還未執行j=6這一行程式碼,所以無法檢視變數j的值。

我們可以使用llistllllist列印附近11行原始碼,ll列印全部原始碼)來檢視執行到了原始碼的什麼位置,下圖中的->指示出程式碼執行到了哪一行:

這裡要注意上圖是將要執行第4行,但還沒有執行。還要注意,這一行是個函式呼叫。我們繼續輸入steplist,我們發現程式碼跳入13行函式體中了:

除了p命令,我們還可以使用a或者args命令檢視當前函式的引數列表。

一般說來,除錯時遇到函式呼叫,我們先看呼叫結果對不對,結果正確,說明函式沒有問題,就不用進入函式體了;如果函式呼叫結果不對,我們才需要進入函式體進行除錯。單步跟蹤命令nextstep在執行一般語句時沒有區別,在執行有函式呼叫的語句時,next會把函式執行完,step會進入函式體。所以在除錯時,單步執行我們要優先使用next,這樣效率比較高。

現在已經進入函式體了,我們可以執行up把函式執行完,返回到呼叫處,在這之後執行一般語句,你會發現nextstep沒有區別。

第8行和第9行是個迴圈,這兩條語句單步執行起來有點費勁。

我們可以通過b 11在第11行設個斷點,然後執行ccont命令就會一下子把迴圈執行完並停在第十二行。cont是continue的縮寫,功能是執行到下一個斷點處停止。

我們可以用break命令檢視設定的斷點的情況。

其實,這裡最好設定的是臨時斷點tbreak——在第一次執行到這個斷點之後,就自動刪除這個斷點,用法和b一樣。

還有,如果第8行問題出在i=80處,我們就需要使用條件斷點。

條件斷點的設定方法是,需要先設定一個斷點或臨時斷點,然後引用該斷點的編號breaknumber,設定條件語句。

這裡我重新啟動了Pdb,我在第9行設定了一個臨時斷點,它的斷點編號breaknumber是3,我希望在i=80的時候停下來,那麼根據condition breaknumber condition的輸入規則,我們只要輸入condition 3 i==80即可,當判斷i==80返回True的時候,就會接受斷點。

繼續執行下去在第9行停了下來,這個時候可以檢視i的值為80

這個時候再檢視現有斷點,可以看到第9行的臨時斷點已經被刪除了。

最後,我們使用qquit可以退出Pdb。

類的除錯——遞迴的學習

遞迴演算法是一種直接或間接地呼叫自身的演算法。在編寫程式時,遞迴演算法對解決一大類問題是十分有效的,它往往使演算法的描述簡潔而且易於理解。

遞迴用於解決形式相同,規模不同的問題,能用遞迴解決的問題都可以轉化為迴圈。遞迴把一個大型複雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解,遞迴策略只需少量的程式就可描述出解題過程所需要的多次重複計算,大大地減少了程式的程式碼量。遞迴的能力在於用有限的語句來定義物件的無限集合。用遞迴思想寫出的程式往往十分簡潔易懂。

遞迴程式有兩個要點:遞迴公式和結束條件。我們以求整數的階乘為例:

有了公式,程式碼就容易寫出來了:

class Factorial:
    def fact(self, n):
        if n==0:
            return 1
        else:
            return n * self.fact(n-1)

def main():
    my = Factorial()
    print(my.fact(5))

main()

fact(5)的遞推過程如下圖:

進入除錯,我們設定好斷點,開始執行:

類的方法呼叫一次就會形成一個棧幀,我們在Pdb中用where顯示棧幀,用updown可以在棧幀之間跳轉。

大家用四次up,四次down 體會一下壓棧,出棧,其中>顯示了棧幀位置:

感謝謝繹同學幫忙改寫Pyhton版本.

參考資料


歡迎關注“rocedu”微信公眾號(手機上長按二維碼)

做中教,做中學,實踐中共同進步!



如果你覺得本文對你有幫助,請點一下左下角的“好文要頂”和“收藏該文