首頁  >  文章  >  後端開發  >  python調試工具pdb的用法匯總(Python Debugger)

python調試工具pdb的用法匯總(Python Debugger)

WBOY
WBOY轉載
2022-11-07 16:46:036283瀏覽

本篇文章為大家帶來了關於Python的相關知識,其中主要介紹了關於pdb調試工具的相關內容,包括了pdb基本命令、用break設置斷點等等內容,下面一起來看一下,希望對大家有幫助。

python調試工具pdb的用法匯總(Python Debugger)

【相關推薦:Python3影片教學

一、pdb 有2種用法

pdb: python debugger

1、非侵入式方法 (不用額外修改原始程式碼,在命令列下直接運行就能調試)

python3 -m pdb filename.py

2、侵入式方法(需要在被偵錯的程式碼中加入以下程式碼然後再正常執行程式碼)

import pdb pdb.set_trace()

當你在命令列看到下面這個提示符號時,說明已經正確開啟了pdb

(Pdb)

二、pdb 基本指令

## break 或bcontinue 或c##list 或l查看目前行的程式碼段step 或s#進入函數(進入for 迴圈用next 而不是用step)return 或r執行程式碼直到從目前函數回傳next 或n執行下一行up 或u回到上個呼叫點(不是上一行)p x列印變數x的值
指令 #解釋
設定斷點
繼續執行程式
#########exit 或q#######中止調試,退出程式###########help######幫助# ###########

在實際使用中發現,用shell腳本執行python檔案時,可能無法用pdb調試,會退出。此時只能直接執行py檔來調試。

三、在指定檔案的指定位置,用break指令設定斷點

#3.1 在本檔案中的指定位置設定斷點

例如下面的例子,若要進入到模型的forward() 方法中查看前向傳播過程中的資料處理過程,只能在 forward() 的第一行(即26行)設定斷點,pdb.set_trace()

但有時候模型很複雜,用這個方法會導致程式報錯直接退出(我也不知道是什麼原因),那我們就可以考慮用break 指令在這裡一行插入斷點,使得程式運行到forward() 時就會停下來。

import torchimport torch.nn as nnimport pdbclass EncoderLayer(nn.Module):    def __init__(self):        super().__init__()
        self.conv1 = nn.Conv2d(4, 10, (3, 3))
        self.conv2 = nn.Conv2d(10, 4, (3, 3))
        self.relu = nn.ReLU()    def forward(self, x):
        x=self.relu(self.conv1(x))        return self.relu(self.conv2(x))class Encoder(nn.Module):    def __init__(self,num_layers):        super().__init__()        # encoders 由 num_layers个 EncoderLayer子层组成,每个子层结构相同,但参数不一定相同。
        self.ModelList = nn.ModuleList([EncoderLayer() for _ in range(num_layers)])    def forward(self, x):        # ModuleList是一个list,只能通过list的操作方式(如用for循环、下标索引等)进行forward计算。
        for layer in self.ModelList:
            x = layer(x)        return xif __name__=="__main__":
    pdb.set_trace()   
    input = torch.rand(5, 4, 30, 30)
    model = Encoder(num_layers=4)
    output = model(input)

具體方法: (1)先在前面的任一行設定 pdb.set_trace() ,使得程式停下來。 (2)輸入 break 26 就可以了。如圖:

python調試工具pdb的用法匯總(Python Debugger)這樣斷點就設定成功了,程式運行到forward()就會停下來。

這裡的26是行數,需要注意的是斷點位置不能是註解,例如我們在25行(註解行)設定斷點,就會失敗:

python調試工具pdb的用法匯總(Python Debugger)總結一下,在同一個檔案中設定斷點的指令是:

break line

3.2 在其他檔案中的指定位置設定斷點

如果想要設定的斷點不在初始運作檔案裡面呢,怎麼在其他檔案中用break指令設定斷點呢?我們來看這個例子:

把3.1的程式碼分成三個py文件,放下同一路徑下:

  ![python調試工具pdb的用法匯總(Python Debugger)](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4b5d476ba5b14b0ba541d78930b9704a~tplv-k3u1fbpfcp-zoom-1.image)

看一下每個文件的內容:

run.py:

初始的pdb.set_trace() 設定在run.py中。

import torchfrom encoder import Encoderimport pdbif __name__=="__main__":
    pdb.set_trace()    input = torch.rand(5, 4, 30, 30)
    model = Encoder(num_layers=4)
    output = model(input)

encoder.py:

from encoder_layer import EncoderLayerimport torch.nn as nnclass Encoder(nn.Module):    def __init__(self,num_layers):        super().__init__()        # encoders 由 num_layers个 EncoderLayer子层组成,每个子层结构相同,但参数不一定相同。
        self.ModelList = nn.ModuleList([EncoderLayer() for _ in range(num_layers)])    def forward(self, x):        # ModuleList是一个list,只能通过list的操作方式(如用for循环、下标索引等)进行forward计算。
        for layer in self.ModelList:
            x = layer(x)        return x

encoder_layer.py:

import torch.nn as nnclass EncoderLayer(nn.Module):    def __init__(self):        super().__init__()
        self.conv1 = nn.Conv2d(4, 10, (3, 3))
        self.conv2 = nn.Conv2d(10, 4, (3, 3))
        self.relu = nn.ReLU()    def forward(self, x):
        x=self.relu(self.conv1(x))        return self.relu(self.conv2(x))

現在我們執行run.py ,然後在encoder.py 的第12行設定斷點,即

for layer in self.ModelList:

指令為:

#break encoder.py:12

即break filename:linepython調試工具pdb的用法匯總(Python Debugger)我們可以看到,程式可以從 output = model(input) 進入forward():python調試工具pdb的用法匯總(Python Debugger)這樣可以很方便地進行調試。

如果初始斷點與目標斷點不在同一個目錄下的檔案中,也可以透過相對路徑下的檔案名稱設定斷點,如:

(Pdb) break ../transformer/asr_model.py:91Breakpoint 1 at /local/wenet/examples/aishell/s0/wenet/transformer/asr_model.py:91(Pdb)

四、使用pdb 時發現的問題

4.1 使用軟連結時,pdb 顯示的檔案路徑與實際路徑不一致的問題

如圖可以發現,pdb有三行組成,第一行時檔案路徑,第二行是目前執行的程式碼行,第三行是輸入命令列。

在存在軟連結時,pdb顯示的路徑是軟連結指向的路徑,但實際上的程式碼路徑是拷貝了軟連接內容的路徑,這兩個路徑不一樣,一定要注意。 python調試工具pdb的用法匯總(Python Debugger)

4.2 pdb有時候無法在模型的forward() 方法中加入斷點

pdb有時候無法用pdb. set_trace() 在模型的forward() 方法中加入斷點,報錯內容為:

Compiled functions can't take variable number of arguments or use keyword-only arguments with defaul

大概意思是「編譯後的函數不能接受數量可變的參數,也不能在default中使用僅關鍵字參數。」

不懂啥意思,這個問題也沒有解決。

五、程式奔潰後的事後調試:pdb.pm()

前面所述都是在程式開始運行時就插入斷點,用pdb進行調試,即事前調試。其實 pdb 還可以進行事後調試,即在程式有bug運行奔潰後用python調試器進行查看。

例如test.py 顯然是有bug 的:

# test.pydef add(n):    return n+1add("hello")

直接運行:

python test.py

程式奔潰:

F:\PycharmProjects\pytorch_practice>python test.py
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    add("hello")
  File "test.py", line 2, in add
    return n+1
TypeError: can only concatenate str (not "int") to str</module>

這樣我們是無法用pdb進行調試的。那麼當程式崩潰後,我們該怎麼去調試呢?

我們可以用下面這個指令來簡單偵錯:

python -i test.py

-i 選項可以讓程式結束後開啟一個互動式shell,如下:

F:\PycharmProjects\pytorch_practice>python -i test.py
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    add("hello")
  File "test.py", line 2, in add
    return n+1
TypeError: can only concatenate str (not "int") to str
>>></module>

现在我们发现程序结束后出现了 >>> 符号,这就是python调试器。

输入命令:

import pdb pdb.pm()

其中 pdb.pm() 用于程序发生异常导致奔溃后的事后调试,可以跟踪异常程序最后的堆在信息。

执行命令后得到:

TypeError: can only concatenate str (not "int") to str
>>> import pdb
>>> pdb.pm()
> f:\pycharmprojects\pytorch_practice\test.py(2)add()
-> return n+1
(Pdb)

可以发现,pdb.pm() 已经追踪到了导致程序奔溃的语句:return n+1

此时可以打印 n 的值进行检查:

(Pdb) p n'hello'(Pdb) q>>> quit()

F:\PycharmProjects\pytorch_practice>

q 表示退出pdb调试,quit() 表示退出 python 调试器。

【相关推荐:Python3视频教程

以上是python調試工具pdb的用法匯總(Python Debugger)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.im。如有侵權,請聯絡admin@php.cn刪除