當前位置:
首頁 > 知識 > 三步學會 Debug 神器,效率提升不少!

三步學會 Debug 神器,效率提升不少!

三步學會 Debug 神器,效率提升不少!

打開今日頭條,查看更多圖片

PDB是Python自帶的一個包,為Python程序提供了一種交互的源代碼調試功能,主要特性包括設置斷點、單步調試、進入函數調試、查看當前代碼、查看棧片段、動態改變變數的值等。

啟動調試工具

使用PDB的第一步是讓解釋器在適當的時候進入調試工具。可以採用很多不同的方法

達到這個目的,具體取決於起始條件和所要調試的內容。

從命令行執行:

PDB的最直接的方式是通過命令行運行,命令格式如下:

python3 -m pdb py文件

這裡我們來個小例子,有一個文件名為1.py,代碼如下:

def foo(num):
print(f"當前的數字是:{num}")
if __name__ == "__main__":
foo(3)

然後再命令行中定位到當前位置。

三步學會 Debug 神器,效率提升不少!

通過命令行運行PDB

通常PDB在列印一個文件名時會在輸出中包含各模塊的完整路徑,然後會顯示出下一行將要運行的代碼。這個裡的話就是接下來將運行函數foo了。

在解釋器中運行:

如果在互動式環境下運行調試工具,可以使用run()或者runeval()。

在程序中運行:

上面的情況只是適合一開始就啟動調試工具,對於長時間的而且需要運行一段時間才去進行調試的情況,更方便的做法就是在需要運行的代碼之前加set_trace()方法了。

set_trace()可以在任意位置進行調用,像下面的例子。

import pdb
def foo(num):
print(f"當前的數字是:{num}")
for i in range(num):
pdb.set_trace()
print(f"當前循環的數字:{i}")
if __name__ == "__main__":
foo(10)

三步學會 Debug 神器,效率提升不少!

上面的代碼在for循環中打了一個斷點,可以發現我們程序停在了for循環的位置,然後顯示出下一行將要執行的內容

print(f"當前循環的數字:{i}")
怎麼知道循環到第幾個數字呢?

答:通過直接輸入變數i可以看到當前的值。

怎麼知道當前的代碼運行到哪了?

答:通過命令where(簡寫w)可以得出正在執行哪一行,以及程序的調用棧的位置。

如何查看附近當然代碼附近的代碼信息?

答:通過list(簡寫l)可以看周圍的代碼默認是上5行、下5行。另外命令longlist(簡寫ll)可以輸出當前的函數的源碼。如果需要看整個類的源碼可以通過source+類名獲取源碼。

三步學會 Debug 神器,效率提升不少!

三步學會 Debug 神器,效率提升不少!

常用命令

步驟執行:

step(簡稱s):函數單步執行,如果遇到函數會進入函數內部繼續調試,如果不需要進入函數體只是一步一步執行,此時就要用下面的next了。

next(簡稱n):單步執行命令,不會進入函數體,但是向之前說的那個如果遇到了一個for循環10次還好如果是10000次呢,此時就要用到下面的命令了。

until:該命令類型next,只不過它會繼續執行,直到執行到同一個函數中行號大於當前值的一行,也就是說可以用until跳出循環末尾。當然until也可以指定一個比當前行號大的值,調到指定位置。

一個例子:

import pdb
class Myobj():
def foo(self,num):
print(f"當前的數字是:{num}")
pdb.set_trace()
for i in range(num):
print(f"當前循環的數字:{i}")
print("over")
if __name__ == "__main__":
m=Myobj()
m.foo(4)

三步學會 Debug 神器,效率提升不少!

可以發現執行until把整個循環走了一遍,然後到下一行也就是。

-> print("over")
return:return也可以繞開一段代碼的捷徑,只不過它會繼續執行。
直至函數準備執行一個return語句,然後會暫停,使得在函數返回之前可以看到返回值。

一個沒什麼實際用途的例子,不過可以很好地演示這個效果。

import pdb
lst=[]
class Myobj():
def foo(self,num):
print(f"當前的數字是:{num}")
pdb.set_trace()
for i in range(num):
print(f"當前循環的數字:{i}")
lst.append(i)
return lst
if __name__ == "__main__":
m=Myobj()
m.foo(4)

三步學會 Debug 神器,效率提升不少!

斷點相關:

break(簡稱b): 當然隨著代碼的增長即使使用return和until或者next都很費時間,此時就要考慮在指定位置設置斷點的方式了,如果要在文件的一個特定行設置斷點,可以使用break lineno,然後通過下面的continue(簡寫c)命令調到下一個斷點。

我們還可以指定在某個函數中設置斷點比如:break Myobj().foo。

除此之外還可以執行其他文件設置斷點,也可以相當於sys.path上將某個文件的相對路徑。如果只執行break命令可以看到哪些地方有斷點,包括哪個文件行號等信息。

disable:可以指定上面break之後顯示的斷點,執行後可以發現之前Enb欄有yes變為false。此時輸入l可以看到打斷點的為會有B標識。

如果想徹底刪除就需要執行clear命令了。

三步學會 Debug 神器,效率提升不少!

添加和刪除斷點效果展示圖

clear:徹底刪除一個斷點,使用方式clear id號,類型disable。

tbreak:臨時斷點,程序第一次執行到臨時斷點時會自動清除。不用再去手動刪除了。

條件斷點:

可以對斷點應用一些規則,以便其僅當條件滿足時才執行。與手動啟用和禁用斷點相比,使用條件斷點可以更好地控制調試器暫停程序的方式。

條件斷點可以通過兩種方式設置。第一種方法是指定使用break設置斷點時的條件。使用方法是代碼行號加表達式。看一個應用例子。

import pdb
lst = []
class Myobj():
pdb.set_trace()
def foo(self, num):
print(f"當前的數字是:{num}")
if __name__ == "__main__":
m = Myobj()
[m.foo(i) for i in range(10)]

三步學會 Debug 神器,效率提升不少!

解析下圖中命令的含義:

1.break 10,num>5,是指在第10行打斷點,然後條件是num>5的時候,通過後面輸出break可以看到具體的斷點信息,很明顯看到我們的斷點條件。

stop only if num>5

2.如果表達式的計算結果為true,則執行將在斷點處停止。

除此之外,還可以使用條件命令將條件應用於現有斷點。參數是斷點id和表達式。

還是上面的代碼讓我們看效果圖。

三步學會 Debug 神器,效率提升不少!

忽略斷點

如果在循環的過程中想忽略前幾條結果,比如這裡忽略前3個,就可以使用ignore。

使用方法是:

ignore 斷點id 忽略次數。
如果在運行之前不想忽略了可以使用下面命令,如果已經運行continue了的話就沒效果了。
ignore 斷點id 0

三步學會 Debug 神器,效率提升不少!

監視變數:

display:有時候我們需要實時觀察一個變數的變化,這個時候dispaly就是最好的幫手,如果想移出可以使用undisplay。

三步學會 Debug 神器,效率提升不少!

display監視變數

改變工作流:

jump:jump命令在運行時改變程序的流程,而不修改代碼。 它可以向前跳過以避免運行某些代碼,也可以向後跳轉以再次運行它。

import pdb
def f(n):
pdb.set_trace()
result = []
j = 0
for i in range(n):
j = i * n + j
j += n
result.append(j)
return result
if __name__ == "__main__":
print(f(5))

向前跳:

向前跳轉會將執行點移動到當前位置之後,而不會執行期間任何語句。

三步學會 Debug 神器,效率提升不少!

向後跳:

跳轉還可以將程序執行移動到已經執行的語句中,以便再次運行它。

不允許的jump方式

1.跳入和跳出某些流控制語句,無法判斷什麼時候進入。

2.跳轉可以用來輸入函數,但是不給參數,代碼也不能工作。

3.跳轉不會進入for循環或try:except語句等塊的中間。

4.finally塊中的代碼必須全部執行,因此跳轉不會離開該塊。

5.最基本的限制是跳轉被限制在調用堆棧的底部框架上。 向上移動堆棧以檢查變數後,此時無法更改執行流程。

其他命令

  • up(簡稱u):可以向棧中較舊的幀移動
  • down(簡稱d):可以向棧中較新的幀移動。每次在棧中上移或者下移時,調試工具都會列印當前位置,格式與where生成的格式相同。
  • args(簡稱a):可以列印當前函數的所有參數的值。
  • p和pp:這兩個是類似python的print和pprint的功能。輸出信息的,pp帶有美化功能。
  • !:在一個表達式前面加一個!,可以修改python程序當前正在運行的值,比如上面的例子num等於10,如果執行!num=3,後面再輸出num你會看到此時的num變成3了,這個可以減少測試時候我們的循環次數了。當然這個循環次數是否可以變動還是看程序的邏輯。
  • 參考資料

https://docs.python.org/3.7/library/pdb.html

作者簡介:陳祥安,高級爬蟲工程師,從業多年,有著豐富的爬蟲工作經驗,從c#語言轉入到Python語言,擅長各種爬蟲技術,熟悉大規模爬蟲開發,熱愛並喜歡鑽研Python。歡迎大家和我一起來交流學習。

本文系作者投稿,版權歸作者所有。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 CSDN 的精彩文章:

SQL 已死,但 SQL 將永存!
流量為王,程序員如何打破 8 秒原則?| 技術頭條

TAG:CSDN |