python 2.7 pdb官方文檔:https://docs.python.org/2.7/library/pdb.html
pdb是ptyhon內置的一個調試庫,是調試python代碼的好幫手,本文是對其用法的詳細介紹。
QuickStart
待調試的代碼內容
文件名:test.py:
# coding:utf-8
import pdb
s1 = 'aaa'
pdb.set_trace()
s2 = 'bbb'
s3 = 'ccc'
pdb.set_trace()
s = s1 + s2 + s3
print s
可以看出在代碼的第4、7行分別打了一個斷點,使用的是pdb.set_trace()
函數。
開始調試
在和代碼文件相同路徑下打開命令行窗口,輸入命令:python test1.py
接著就進入了調試狀態:
(.env) E:\code\python-basic\tools\pdb\sample>python test1.py
> e:\code\python-basic\tools\pdb\sample\test1.py(5)<module>()
-> s2 = 'bbb'
(Pdb)
可以看出直接執行到了第一個斷點所在的下一行,并停在了這里。
這時可以執行命令:n
進行下一步:
(Pdb) n
> e:\code\python-basic\tools\pdb\sample\test1.py(6)<module>()
-> s3 = 'ccc'
(Pdb)
使用p <變量名>
命令打印已經出現過的變量的值:
(Pdb) p s1
'aaa'
(Pdb) p s2
'bbb'
(Pdb) p s3
*** NameError: NameError("name 's3' is not defined",)
(Pdb)
因為當前變量s3還沒有被賦值,所以打印s3的時候提示NameError
異常。
使用l
命令打印出當前的代碼段:
(Pdb) l
1 # coding:utf-8
2 import pdb
3 s1 = 'aaa'
4 pdb.set_trace()
5 s2 = 'bbb'
6 -> s3 = 'ccc'
7 pdb.set_trace()
8 s = s1 + s2 + s3
9 print s
[EOF]
(Pdb)
退出調試:q
命令
(Pdb) q
Traceback (most recent call last):
File "test1.py", line 6, in <module>
s3 = 'ccc'
File "test1.py", line 6, in <module>
s3 = 'ccc'
File "d:\programs\python27\Lib\bdb.py", line 49, in trace_dispatch
return self.dispatch_line(frame)
File "d:\programs\python27\Lib\bdb.py", line 68, in dispatch_line
if self.quitting: raise BdbQuit
bdb.BdbQuit
(.env) E:\code\python-basic\tools\pdb\sample>
PDB調試的另一種方式
QuickStart中使用的調試方式不夠優雅,因為是通過修改代碼的方式打斷點的,用起來不太方便。那么能不能動態打斷點呢?答案是當然可以,請接著往下看。
準備待調試的代碼
刪除掉QuickStart中代碼中的pdb.set_trace()
,剩下的代碼如下:
文件名:test2.py
# coding:utf-8
s1 = 'aaa'
s2 = 'bbb'
s3 = 'ccc'
s = s1 + s2 + s3
print s
開始調試
在test2.py相同路徑下打開命令行,輸入命令:python -m pdb test2.py
(.env) E:\code\python-basic\tools\pdb\sample>python -m pdb test2.py
> e:\code\python-basic\tools\pdb\sample\test2.py(2)<module>()
-> s1 = 'aaa'
(Pdb) l
1 # coding:utf-8
2 -> s1 = 'aaa'
3 s2 = 'bbb'
4 s3 = 'ccc'
5 s = s1 + s2 + s3
6 print s
[EOF]
(Pdb)
可以看到當前代碼中我們還沒有打任何斷點,代碼默認停在了第1行。
執行一個命令n
:
(Pdb) n
> e:\code\python-basic\tools\pdb\sample\test2.py(3)<module>()
-> s2 = 'bbb'
(Pdb) l
1 # coding:utf-8
2 s1 = 'aaa'
3 -> s2 = 'bbb'
4 s3 = 'ccc'
5 s = s1 + s2 + s3
6 print s
[EOF]
(Pdb)
可以看到單步執行到了下一行。
如果我們想在第5行打一個斷點,該怎么打呢?用b <行號>
命令在某一行打一個斷點:
(Pdb) b 5
Breakpoint 1 at e:\code\python-basic\tools\pdb\sample\test2.py:5
(Pdb) l
[EOF]
(Pdb) n
> e:\code\python-basic\tools\pdb\sample\test2.py(4)<module>()
-> s3 = 'ccc'
(Pdb) l
1 # coding:utf-8
2 s1 = 'aaa'
3 s2 = 'bbb'
4 -> s3 = 'ccc'
5 B s = s1 + s2 + s3
6 print s
[EOF]
(Pdb)
這樣就成功地在第5行打了一個斷點。
查看當前打了哪些斷點:b
命令
(Pdb) b
Num Type Disp Enb Where
1 breakpoint keep yes at e:\code\python-basic\tools\pdb\sample\test2.py:5
(Pdb)
PDB調試命令匯總
高級命令
以上的示例只是展示了最簡單的順序結構的代碼的調試方法,而實際應用中遇到的大多數代碼都有著較為復雜的邏輯結構,比如循環結構、分支結構、調用函數、調用其他模塊的函數、使用類和對象等等。
針對這些場景還有很多更高級的調試命令,其實掌握了前面的幾個簡單的命令的用法后,下面的這些更高級的命令就都很容易上手了,多用幾遍就能很快掌握了。
命令 | 命令全稱 | 功能 |
---|---|---|
h | help | 查看幫助 |
n | next | 執行下一條語句 |
s | step | 執行下一條語句,如果是函數,則會執行到函數的第一句 |
b | break | 列出當前的所有斷點 |
b <行號> | / | 在某一行打一個斷點 |
b <文件名>:<行號> | / | 在某個文件的某行打一個斷點 |
b <函數名> | / | 在某個函數的第一行打一個斷點 |
cl | clear | 清除所有斷點 |
cl n1 n2 ... | / | 清除編號為n1、n2...的斷點 |
cl <行號> | / | 清除某行的斷點 |
cl <文件名>:<行號> | / | 清除某個文件某行的斷點 |
r | return | 執行當前函數到結束 |
c | continue | 執行到下一個斷點 |
l | list | 列出源碼(前后11行代碼) |
l <行號> | / | 列出某行周圍11行代碼 |
l <行號1> <行號2> | / | 列出兩個行號范圍內的代碼 |
p <變量名> | print <變量名> | 輸出變量的值 |
pp <變量名> | / | 好看一點的輸出 |
q | quit | 退出debug |
unt | until | 退出循環或當期堆棧 |
run | / | 重新啟動debug |
a | args | 列出當前執行的函數的參數 |
w | where | 打印當前執行堆棧 |
注:平時使用的時候通常用的都是各個命令的簡寫形式,當然用全稱也是可以的(如果不嫌麻煩的話)。
補充
- 在命令行中進入調試模式的方法:
python -m pdb demo.py
- 在調試模式中按一下
Enter
鍵表示執行一下上一條命令。 - 在ipython中使用PDB(體驗更好):
%run -d demo.py