pytorch Debug —交互式調試工具Pdb (ipdb是增強版的pdb)-1-使用說明


初學時大多使用print或log調試程序,這在小規模的程序下很方便

但是更好的方法是一邊運行一邊檢查里面的變量和方法

1.Pdb

Pdb是一個交互式的調試工具,集成於Python標准庫中

Pdb能讓你根據需求跳轉到任意的Python代碼斷點、查看任意變量、單步執行代碼,甚至還能修改變量的值,而不必重啟程序

⚠️pdb 調試有個明顯的缺陷就是對於多線程,遠程調試等支持得不夠好,同時沒有較為直觀的界面顯示,不太適合大型的 python 項目。

而在較大的 python 項目中,這些調試需求比較常見,因此需要使用更為高級的調試工具,如PyCharm IDE。

手冊:https://docs.python.org/3.5/library/pdb.html#pdbcommand-where

pdb的使用方式和ipdb是一樣的

 

2.ipdb

ipdb是增強版的pdb,參考https://github.com/gotcha/ipdb

1)安裝:

(deeplearning) userdeMacBook-Pro:dogcat-6 user$ pip install ipdb
Requirement already satisfied: ipdb in /anaconda3/envs/deeplearning/lib/python3.6/site-packages (0.12)
...

ipdb提供了調試模式下的代碼自動補全,還具有更好的語法高亮和代碼溯源,以及更好的內省功能。它與pdb接口完全兼容

 

2)結合PyTorch和ipdb進行調試

1》集成到源代碼中

要使用ipdb,只需要在想要進行調試的地方插入語句:

import ipdb
ipdb.set_trace() #相當於添加斷點

當代碼運行到這里,就會自動進入交互式調試模式

上面的方式雖然簡單,但是存在着兩個較為比較明顯的問題:

  1. 插入的斷點代碼會污染原來的代碼空間 
  2. 每次插入斷點都需要修改源碼
try:
    import ipdb
except:
    import pdb as ipdb
    
def sum(x):
    r = 0
    for ii in x:
        r += ii
    return r

def mul(x):
    r =1
    for ii in x:
        r *= ii
    return r

ipdb.set_trace()
x = [1,2,3,4,5]
r = sum(x)
r = mul(x)

當程序運行到ipdb.set_trace()語句時,會自動進入debug模式,在該模式中,我們可使用調試命令,如next或縮寫n實現單步執行;也可以查看Python變量,或是運行Python代碼

如果Python變量名和調試命令沖突,需在變量名前加!,這樣ipdb會執行對應的Python命令,而不是調試命令

下面舉例說明ipdb的調試

這里重點講解ipdb的兩大功能:

  • 查看:在函數調用堆棧中自由跳動,並查看函數的局部變量
  • 修改:修改程序中的變量,並能以此影響程序的運行結果

將上面的命令生成ipdb_test.py文件,使用命令行進行調試

(deeplearning) userdeMacBook-Pro:pytorch-learning user$ python ipdb_test.py
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(19)<module>()
     18 ipdb.set_trace()
---> 19 x = [1,2,3,4,5]
     20 r = sum(x)

--->光標所指處為運行到的代碼

 

下面進行說明調試時能夠使用的命令:

l 1,18 : list 1,18的縮寫,查看第1行到18行的代碼

ipdb> l 1,18                                                                    
      1 try:
      2     import ipdb
      3 except:
      4     import pdb as ipdb
      5 
      6 def sum(x):
      7     r = 0
      8     for ii in x:
      9         r += ii
     10     return r
     11 
     12 def mul(x):
     13     r =1
     14     for ii in x:
     15         r *= ii
     16     return r
     17 
     18 ipdb.set_trace()

 

n : next的縮寫,執行下一步;如果當前語句有一個函數調用,用 n 是不會進入被調用的函數體中的

ipdb> n                                                                         
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(20)<module>()
     19 x = [1,2,3,4,5]
---> 20 r = sum(x)
     21 r = mul(x)

 

s : step的縮寫,進入函數sum內部

ipdb> s                                                                         
--Call--
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(6)sum()
      5 
----> 6 def sum(x):
      7     r = 0

 

再繼續單步執行,再在函數中繼續執行,耶可以不用輸入n,直接回車則會使用上次的命令

ipdb> n                                                                         
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(7)sum()
      6 def sum(x):
----> 7     r = 0
      8     for ii in x:

ipdb> n                                                                         
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(8)sum()
      7     r = 0
----> 8     for ii in x:
      9         r += ii

ipdb> n                                                                         
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(9)sum()
      8     for ii in x:
----> 9         r += ii
     10     return r

 

u : up的縮寫,跳回上一層的調用

ipdb> u                                                                         
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(20)<module>()
     19 x = [1,2,3,4,5]
---> 20 r = sum(x)
     21 r = mul(x)

 

d : down的縮寫,跳回之前調用到的下一層的位置

ipdb> d                                                                         
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(9)sum()
      8     for ii in x:
----> 9         r += ii
     10     return r

 

當查看變量的命令和調試命令起沖突時,在前面加一個!

查看r變量,該變量名與調試命令r(eturn) 起沖突

ipdb> !r                                                                        
0

 

return : 繼續運行,直到函數返回,結束該sum()函數的運算

ipdb> return                                                                    
--Return--
15
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(10)sum()
      9         r += ii
---> 10     return r
     11 

 

當命令和調試命令沒有沖突的時候,可以直接運行,不用添加!

這里查看變量x的值,並對變量值進行修改

ipdb> n                                                                         
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(21)<module>()
     19 x = [1,2,3,4,5]
     20 r = sum(x)
---> 21 r = mul(x)

ipdb> x                                                                         
[1, 2, 3, 4, 5]
ipdb> x[0] = 10000 

 

b 13 : break的縮寫,在13行處添加一個斷點,如果沒有添加位置則輸出所有的斷點信息

ipdb> b 13                                                                      
Breakpoint 1 at /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py:13

 

c : continue的縮寫,繼續運行,直到遇到斷點

ipdb> c                                                                         
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(13)mul()
     12 def mul(x):
1--> 13     r =1
     14     for ii in x:

ipdb> return                                                                    
--Return--
1200000
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(16)mul()
     15         r *= ii
---> 16     return r
     17 

return后得到的是修改后的x的乘積

 

l(ist) 或 ll : ll 是查看整個源碼文件,l 可指定需要查看的行數,默認是當前往后 11 行,也可指定具體的范圍

ipdb> list                                                                      
     11 
     12 def mul(x):
1    13     r =1
     14     for ii in x:
     15         r *= ii
---> 16     return r
     17 
     18 ipdb.set_trace()
     19 x = [1,2,3,4,5]
     20 r = sum(x)
     21 r = mul(x)

 

pp 或 p expression: 打印變量的值,兩者的不同是p用的是print(),pp用的是pprint()

ipdb> pp x                                                                      
[10000, 2, 3, 4, 5]
ipdb> x                                                                         
[10000, 2, 3, 4, 5]

 

exit 或 q(uit) : 中止並退出

ipdb> q                                                                         
Exiting Debugger.

 

關於ipdb的使用還又一些技巧:

  • <tab>鍵能夠自動補齊,補齊用法與IPython中的類似
  • 可以直接在ipdb中修改變量的值
  • h(elp)能夠查看調試命令的用法,比如h h可以查看h(elp)命令的用法,h jump能夠查看j(ump)命令的用法

其他命令:

run 或 restart [args ...]:兩者就是別名的關系,重新運行該python調試項目,如果提供了參數,會使用shlex進行分離,並將結果作為新的sys.argv。歷史記錄、斷點、行動和調試選項都會保留。

run [args ...]:這里的參數會作為運行腳本的參數

(deeplearning) userdeMBP:pytorch-learning user$ python -m ipdb ipdb_test.py 
/anaconda3/envs/deeplearning/lib/python3.6/runpy.py:125: RuntimeWarning: 'ipdb.__main__' found in sys.modules after import of package 'ipdb', but prior to execution of 'ipdb.__main__'; this may result in unpredictable behaviour
  warn(RuntimeWarning(msg))
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(1)<module>()
----> 1 def sum(x):
      2     r = 0
      3     for ii in x:

ipdb> run --x [3,3,3,3]                                                         
Restarting ipdb_test.py with arguments:
    --x [3,3,3,3]
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(1)<module>()
----> 1 def sum(x):
      2     r = 0
      3     for ii in x:

ipdb> import sys                                                                
ipdb> sys.argv                                                                  
['ipdb_test.py', '--x', '[3,3,3,3]']

看到上面的結果,等價於 python ipdb_test.py --x [3,3,3,3],這個參數會作為運行sum(x)的參數

如果要得到的是全新的調試器,使用exit 或 q(uit)

 

通過b設置的斷點在重新運行 debug 程序 (命令  restart 或  run) 后會依然保留,如果要忽略這些斷點,有兩種做法:

  • cl(ear) :如果后面帶有參數,就是清除指定的斷點;如果不帶參數就是清除所有的斷點
(deeplearning) userdeMacBook-Pro:pytorch-learning user$ python ipdb_test.py
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(19)<module>()
     18 ipdb.set_trace()
---> 19 x = [1,2,3,4,5]
     20 r = sum(x)

ipdb> b 8                                                                       
Breakpoint 1 at /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py:8
ipdb> cl 1                                                                      
Deleted breakpoint 1 at /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py:8
ipdb> c       
(deeplearning) userdeMacBook-Pro:pytorch-learning user$ 

因為設置的斷點被清除了,所以運行c會直接結束

 

  • disable/enable :禁用/激活斷點
(deeplearning) userdeMacBook-Pro:pytorch-learning user$ python ipdb_test.py
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(19)<module>()
     18 ipdb.set_trace()
---> 19 x = [1,2,3,4,5]
     20 r = sum(x)

ipdb> b 8                                                                       
Breakpoint 1 at /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py:8
ipdb> b 9                                                                       
Breakpoint 2 at /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py:9
ipdb> disable 1                                                                 
Disabled breakpoint 1 at /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py:8
ipdb> c                                                                         
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(9)sum()
1     8     for ii in x:
2---> 9         r += ii
     10     return r

ipdb>         

因為禁用了8處的斷點,所以運行c直接就到了9的斷點處

 

j(ump) :讓程序跳轉到指定的行數 ,能夠跳過中間某些行代碼的執行

注意:但是必須跳轉的地方在當前的代碼塊中

ipdb> j 13                                                                      
*** Jump failed: line 13 comes after the current code block
ipdb> j 10                                                                      
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(10)sum()
2     9         r += ii
---> 10     return r
     11 

ipdb>   

 

w(here) : 顯示最近的一些棧幀信息

ipdb> w                                                                         
  /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(20)<module>()
     19 x = [1,2,3,4,5]
---> 20 r = sum(x)
     21 r = mul(x)

> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(10)sum()
2     9         r += ii
---> 10     return r
     11 

 

a(rgs) : 返回目前函數的參數列表

ipdb> a                                                                         
x = [1, 2, 3, 4, 5]

這個sum()函數現在的參數就只有一個x

 

2》通過命令行進行交互

這種方法與上面方法不同在於不需要在代碼中插入斷點語句,而是在運行時添加-m參數運行,然后再進行調試

生成ipdb_test_command.py:

#import ipdb  
def sum(x):
    r = 0
    for ii in x:
        r += ii
    return r

def mul(x):
    r =1
    for ii in x:
        r *= ii
    return r

#ipdb.set_trace()
x = [1,2,3,4,5]
r = sum(x)
r = mul(x)

運行:

(deeplearning) userdeMacBook-Pro:pytorch-learning user$ python -m ipdb ipdb_test_command.py
/anaconda3/envs/deeplearning/lib/python3.6/runpy.py:125: RuntimeWarning: 'ipdb.__main__' found in sys.modules after import of package 'ipdb', but prior to execution of 'ipdb.__main__'; this may result in unpredictable behaviour
  warn(RuntimeWarning(msg))
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(2)<module>()
      1 #import ipdb
----> 2 def sum(x):
      3     r = 0

ipdb> n                                                                         
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(8)<module>()
      7 
----> 8 def mul(x):
      9     r =1

ipdb> n                                                                         
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(15)<module>()
     14 #ipdb.set_trace()
---> 15 x = [1,2,3,4,5]
     16 r = sum(x)

ipdb> n                                                                         
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(16)<module>()
     15 x = [1,2,3,4,5]
---> 16 r = sum(x)
     17 r = mul(x)

ipdb> s                                                                         
--Call--
> /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(2)sum()
      1 #import ipdb
----> 2 def sum(x):
      3     r = 0

ipdb>      

-m參數,這樣調用ipdb_test_command.py的話斷點就是程序的執行第一行之前

然后就可以和上面一樣使用命令進行調試

 

3.支持的函數

參考https://docs.python.org/3.5/library/pdb.html#pdbcommand-where

該模塊定義了以下功能;每個進入調試器的方式略有不同:

pdb.set_trace()

  從正在運行的程序中插入調試器的典型用法是插入

import pdb; pdb.set_trace()

在要進入調試器的位置插入上面的函數。然后,你可以按照此語句逐步執行代碼,並使用continue命令在沒有調試器的情況下繼續運行。

大多數情況都只使用set_trace()函數和上面命令進行配合調試,下面的函數使用得比較少,沒能查找到過多下面函數使用的情況,如果有小伙伴有這方面的資料,希望可以告知,謝謝

pdb. run (statement, globals=None, locals=None)

在調試器控制下執行語句(以字符串或代碼對象的形式給出)。調試器提示符出現在執行任何代碼之前;您可以設置斷點並鍵入continue來運行到斷點,或者使用step或next逐步執行語句。可選的全局變量和局部變量指定執行代碼的環境;默認情況下使用模塊__main__的字典。(參見內置的exec()或eval()函數的說明。)

pdb. runeval (expression, globals=None, locals=None)

計算調試器控制器下的表達式(以字符串或代碼對象的形式給出)。當runeval()返回時,它返回表達式的值。否則,這個函數類似於run()。

pdb. runcall (function, *args, **kwds)

使用給定的參數調用函數(函數或方法對象,而不是字符串)。當runcall()返回時,它返回函數調用返回的任何值。一旦輸入函數,調試器提示符就會出現。

pdb. set_trace ()

在調用堆棧幀中輸入調試器。這對於在程序中在給定點硬編碼斷點非常有用,即使代碼沒有被調試(例如,當斷言失敗時)。

pdb. post_mortem (traceback=None)

輸入給定traceback對象的事后調試。如果沒有給出traceback,則使用當前正在處理的異常之一(如果要使用缺省值,則必須處理異常)。

pdb. pm ()

輸入在sys.last_traceback中找到的traceback的事后調試。

run*函數和set_trace()是實例化Pdb類和調用同名方法的別名。如果你想獲得更多的功能,你必須自己做:

class  pdb. Pdb (completekey='tab', stdin=None, stdout=None, skip=None, nosigint=False)

Pdb是調試器類。

completekey、stdin和stdout參數被傳遞給底層cmd.Cmd類;

如果給定了skip參數,則它必須是可迭代的全局樣式模塊名稱模式。調試器不會進入起源於與這些模式之一匹配的模塊中的框架。

默認情況下,當您發出continue命令時,Pdb為SIGINT信號設置一個處理程序(當用戶在控制台上按Ctrl-C時發送該信號)。這允許您通過按Ctrl-C再次進入調試器。如果希望Pdb不接觸SIGINT處理程序,請將nosigint設置為true。

啟用跟蹤與skip的例子調用:

import pdb; pdb.Pdb(skip=['django.*']).set_trace()
新版本3.1:skip參數。

新版本3.2:nosigint參數。以前,Pdb從未設置過SIGINT處理程序。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM