pdb --- Python的調(diào)試器?
源代碼: Lib/pdb.py
pdb 模塊定義了一個交互式源代碼調(diào)試器,用于 Python 程序。它支持在源碼行間設(shè)置(有條件的)斷點和單步執(zhí)行,檢視堆棧幀,列出源碼列表,以及在任何堆棧幀的上下文中運行任意 Python 代碼。它還支持事后調(diào)試,可以在程序控制下調(diào)用。
調(diào)試器是可擴展的——調(diào)試器實際被定義為 Pdb 類。該類目前沒有文檔,但通過閱讀源碼很容易理解它。擴展接口使用了 bdb 和 cmd 模塊。
調(diào)試器的提示符是 (Pdb)。在調(diào)試器的控制下運行程序的典型用法是:
>>> import pdb
>>> import mymodule
>>> pdb.run('mymodule.test()')
> <string>(0)?()
(Pdb) continue
> <string>(1)?()
(Pdb) continue
NameError: 'spam'
> <string>(1)?()
(Pdb)
在 3.3 版更改: 由 readline 模塊實現(xiàn)的 Tab 補全可用于補全本模塊的命令和命令的參數(shù),例如,p 命令的參數(shù)可補全為當(dāng)前的全局變量和局部變量。
也可以將 pdb.py 作為腳本調(diào)用來調(diào)試其他腳本。例如:
python3 -m pdb myscript.py
當(dāng)作為腳本調(diào)用時,如果要調(diào)試的程序異常退出,pdb 調(diào)試將自動進(jìn)入事后調(diào)試。事后調(diào)試之后(或程序正常退出之后),pdb 將重新啟動程序。自動重啟會保留 pdb 的狀態(tài)(如斷點),在大多數(shù)情況下,這比在退出程序的同時退出調(diào)試器更加實用。
3.2 新版功能: pdb.py 現(xiàn)在接受 -c 選項,可以執(zhí)行命令,這與將該命令寫入 .pdbrc 文件相同,請參閱 調(diào)試器命令。
3.7 新版功能: pdb.py 現(xiàn)在接受 -m 選項,該選項用于執(zhí)行一個模塊,類似于 python3 -m。與腳本相同,調(diào)試器將暫停在待執(zhí)行模塊第一行前。
從正在運行的程序進(jìn)入調(diào)試器的典型用法是插入
import pdb; pdb.set_trace()
到你想進(jìn)入調(diào)試器的位置。然后就可以單步執(zhí)行上述語句之后的代碼,要關(guān)閉調(diào)試器繼續(xù)運行,請使用 continue 命令。
3.7 新版功能: 內(nèi)置函數(shù) breakpoint(),當(dāng)以默認(rèn)參數(shù)調(diào)用它時,可以用來代替 import pdb; pdb.set_trace()。
檢查已崩潰程序的典型用法是:
>>> import pdb
>>> import mymodule
>>> mymodule.test()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "./mymodule.py", line 4, in test
test2()
File "./mymodule.py", line 3, in test2
print(spam)
NameError: spam
>>> pdb.pm()
> ./mymodule.py(3)test2()
-> print(spam)
(Pdb)
本模塊定義了下列函數(shù),每個函數(shù)進(jìn)入調(diào)試器的方式略有不同:
-
pdb.run(statement, globals=None, locals=None)? 在調(diào)試器控制范圍內(nèi)執(zhí)行 statement (以字符串或代碼對象的形式提供)。調(diào)試器提示符會在執(zhí)行代碼前出現(xiàn),你可以設(shè)置斷點并鍵入
continue,也可以使用step或next逐步執(zhí)行語句(上述所有命令在后文有說明)。可選參數(shù) globals 和 locals 指定代碼執(zhí)行環(huán)境,默認(rèn)時使用__main__模塊的字典。(請參閱內(nèi)置函數(shù)exec()或eval()的說明。)
-
pdb.runeval(expression, globals=None, locals=None)? 在調(diào)試器控制范圍內(nèi)執(zhí)行 expression (以字符串或代碼對象的形式提供)。
runeval()返回時將返回表達(dá)式的值。本函數(shù)在其他方面與run()類似。
-
pdb.runcall(function, *args, **kwds)? 使用給定的參數(shù)調(diào)用 function (以函數(shù)或方法對象的形式提供,不能是字符串)。
runcall()返回的是所調(diào)用函數(shù)的返回值。調(diào)試器提示符將在進(jìn)入函數(shù)后立即出現(xiàn)。
-
pdb.set_trace(*, header=None)? 在調(diào)用本函數(shù)的堆棧幀處進(jìn)入調(diào)試器。用于硬編碼一個斷點到程序中的固定點處,即使該代碼不在調(diào)試狀態(tài)(如斷言失敗時)。如果傳入 header,它將在調(diào)試開始前被打印到控制臺。
在 3.7 版更改: 僅關(guān)鍵字參數(shù) header。
-
pdb.post_mortem(traceback=None)? 進(jìn)入 traceback 對象的事后調(diào)試。如果沒有給定 traceback,默認(rèn)使用當(dāng)前正在處理的異常之一(默認(rèn)時,必須存在正在處理的異常)。
-
pdb.pm()? 在
sys.last_traceback中查找 traceback,并進(jìn)入其事后調(diào)試。
run* 函數(shù)和 set_trace() 都是別名,用于實例化 Pdb 類和調(diào)用同名方法。如果要使用其他功能,則必須自己執(zhí)行以下操作:
-
class
pdb.Pdb(completekey='tab', stdin=None, stdout=None, skip=None, nosigint=False, readrc=True)? Pdb是調(diào)試器類。completekey、stdin 和 stdout 參數(shù)都會傳遞給底層的
cmd.Cmd類,請參考相應(yīng)的描述。如果給出 skip 參數(shù),則它必須是一個迭代器,可以迭代出 glob-style 樣式的模塊名稱。如果遇到匹配上述樣式的模塊,調(diào)試器將不會進(jìn)入來自該模塊的堆棧幀。 1
默認(rèn)情況下,當(dāng)發(fā)出
continue命令時,Pdb 將為 SIGINT 信號設(shè)置一個處理程序(SIGINT 信號是用戶在控制臺按 Ctrl-C 時發(fā)出的)。這使用戶可以按 Ctrl-C 再次進(jìn)入調(diào)試器。如果希望 Pdb 不要修改 SIGINT 處理程序,請將 nosigint 設(shè)置為 true。readrc 參數(shù)默認(rèn)為 true,它控制 Pdb 是否從文件系統(tǒng)加載 .pdbrc 文件。
啟用跟蹤且?guī)в?skip 參數(shù)的調(diào)用示范:
import pdb; pdb.Pdb(skip=['django.*']).set_trace()
3.1 新版功能: skip 參數(shù)。
3.2 新版功能: nosigint 參數(shù)。在這之前,Pdb 不為 SIGINT 設(shè)置處理程序。
在 3.6 版更改: readrc 參數(shù)。
調(diào)試器命令?
下方列出的是調(diào)試器可接受的命令。如下所示,大多數(shù)命令可以縮寫為一個或兩個字母。如 h(elp) 表示可以輸入 h 或 help 來輸入幫助命令(但不能輸入 he 或 hel,也不能是 H 或 Help 或 HELP)。命令的參數(shù)必須用空格(空格符或制表符)分隔。在命令語法中,可選參數(shù)括在方括號 ([]) 中,使用時請勿輸入方括號。命令語法中的選擇項由豎線 (|) 分隔。
輸入一個空白行將重復(fù)最后輸入的命令。例外:如果最后一個命令是 list 命令,則會列出接下來的 11 行。
調(diào)試器無法識別的命令將被認(rèn)為是 Python 語句,并在正在調(diào)試的程序的上下文中執(zhí)行。Python 語句也可以用感嘆號 (!) 作為前綴。這是檢查正在調(diào)試的程序的強大方法,甚至可以修改變量或調(diào)用函數(shù)。當(dāng)此類語句發(fā)生異常,將打印異常名稱,但調(diào)試器的狀態(tài)不會改變。
調(diào)試器支持 別名。別名可以有參數(shù),使得調(diào)試器對被檢查的上下文有一定程度的適應(yīng)性。
在一行中可以輸入多個命令,以 ;; 分隔。(不能使用單個 ;,因為它用于分隔傳遞給 Python 解釋器的一行中的多條語句。)切分命令很無腦,總是在第一個 ;; 對處將輸入切分開,即使它位于帶引號的字符串之中。
如果文件 .pdbrc 存在于用戶主目錄或當(dāng)前目錄中,則將其讀入并執(zhí)行,等同于在調(diào)試器提示符下鍵入該文件。這對于別名很有用。若兩個文件都存在則首先讀取主目錄中的文件,且本地文件可以覆蓋其中定義的別名。
-
h(elp)[command]? 不帶參數(shù)時,顯示可用的命令列表。參數(shù)為?command 時,打印有關(guān)該命令的幫助。
help pdb顯示完整文檔(即pdb模塊的文檔字符串)。由于 command 參數(shù)必須是標(biāo)識符,因此要獲取!的幫助必須輸入help exec。
-
w(here)? 打印堆棧回溯,最新一幀在底部。有一個箭頭指向當(dāng)前幀,該幀決定了大多數(shù)命令的上下文。
-
d(own)[count]? 在堆?;厮葜?,將當(dāng)前幀向下移動 count 級(默認(rèn)為 1 級,移向更新的幀)。
-
u(p)[count]? 在堆棧回溯中,將當(dāng)前幀向上移動 count 級(默認(rèn)為 1 級,移向更老的幀)。
-
b(reak)[([filename:]lineno | function) [, condition]]? 如果帶有 lineno 參數(shù),則在當(dāng)前文件相應(yīng)行處設(shè)置一個斷點。如果帶有 function 參數(shù),則在該函數(shù)的第一條可執(zhí)行語句處設(shè)置一個斷點。行號可以加上文件名和冒號作為前綴,以在另一個文件(可能是尚未加載的文件)中設(shè)置一個斷點。另一個文件將在
sys.path范圍內(nèi)搜索。請注意,每個斷點都分配有一個編號,其他所有斷點命令都引用該編號。如果第二個參數(shù)存在,它應(yīng)該是一個表達(dá)式,且它的計算值為 true 時斷點才起作用。
如果不帶參數(shù)執(zhí)行,將列出所有中斷,包括每個斷點、命中該斷點的次數(shù)、當(dāng)前的忽略次數(shù)以及關(guān)聯(lián)的條件(如果有)。
-
cl(ear)[filename:lineno | bpnumber [bpnumber ...]]? 如果參數(shù)是 filename:lineno,則清除此行上的所有斷點。如果參數(shù)是空格分隔的斷點編號列表,則清除這些斷點。如果不帶參數(shù),則清除所有斷點(但會先提示確認(rèn))。
-
disable[bpnumber [bpnumber ...]]? 禁用斷點,斷點以空格分隔的斷點編號列表給出。禁用斷點表示它不會導(dǎo)致程序停止執(zhí)行,但是與清除斷點不同,禁用的斷點將保留在斷點列表中并且可以(重新)啟用。
-
enable[bpnumber [bpnumber ...]]? 啟用指定的斷點。
-
ignorebpnumber [count]? 為指定的斷點編號設(shè)置忽略次數(shù)。如果省略 count,則忽略次數(shù)將設(shè)置為 0。忽略次數(shù)為 0 時斷點將變?yōu)榛顒訝顟B(tài)。如果為非零值,在每次達(dá)到斷點,且斷點未禁用,且關(guān)聯(lián)條件計算值為 true 的情況下,該忽略次數(shù)會遞減。
-
conditionbpnumber [condition]? 為斷點設(shè)置一個新 condition,它是一個表達(dá)式,且它的計算值為 true 時斷點才起作用。如果沒有給出 condition,則刪除現(xiàn)有條件,也就是將斷點設(shè)為無條件。
-
commands[bpnumber]? 為編號是 bpnumber 的斷點指定一系列命令。命令內(nèi)容將顯示在后續(xù)的幾行中。輸入僅包含
end的行來結(jié)束命令列表。舉個例子:(Pdb) commands 1 (com) p some_variable (com) end (Pdb)
要刪除斷點上的所有命令,請輸入
commands并立即以end結(jié)尾,也就是不指定任何命令。如果不帶 bpnumber 參數(shù),
commands作用于最后一個被設(shè)置的斷點。可以使用斷點命令來重新啟動程序。只需使用
continue或step命令或其他可以恢復(fù)運行的命令。如果指定了某個繼續(xù)運行程序的命令(目前包括
continue,step,next,return,jump,quit及它們的縮寫)將終止命令列表(就像該命令后緊跟著 end)。因為在任何時候繼續(xù)運行下去(即使是簡單的 next 或 step),都可能會遇到另一個斷點,該斷點可能具有自己的命令列表,這導(dǎo)致要執(zhí)行的列表含糊不清。如果在命令列表中加入 'silent' 命令,那么在該斷點處停下時就不會打印常規(guī)信息。如果希望斷點打印特定信息后繼續(xù)運行,這可能是理想的。如果沒有其他命令來打印一些信息,則看不到已達(dá)到斷點的跡象。
-
s(tep)? 執(zhí)行當(dāng)前行,在第一個可以停止的位置(在調(diào)用的函數(shù)中或在當(dāng)前函數(shù)的下一行)停下。
-
n(ext)? 繼續(xù)運行,直到運行到當(dāng)前函數(shù)的下一行,或當(dāng)前函數(shù)返回為止。(
next和step之間的區(qū)別在于,step進(jìn)入被調(diào)用函數(shù)內(nèi)部并停止,而next(幾乎)全速運行被調(diào)用函數(shù),僅在當(dāng)前函數(shù)的下一行停止。)
-
unt(il)[lineno]? 如果不帶參數(shù),則繼續(xù)運行,直到行號比當(dāng)前行大時停止。
如果帶有行號,則繼續(xù)運行,直到行號大于或等于該行號時停止。在這兩種情況下,當(dāng)前幀返回時也將停止。
在 3.2 版更改: 允許明確給定行號。
-
r(eturn)? 繼續(xù)運行,直到當(dāng)前函數(shù)返回。
-
c(ont(inue))? 繼續(xù)運行,僅在遇到斷點時停止。
-
j(ump)lineno? 設(shè)置即將運行的下一行。僅可用于堆棧最底部的幀。它可以往回跳來再次運行代碼,也可以往前跳來跳過不想運行的代碼。
需要注意的是,不是所有的跳轉(zhuǎn)都是允許的 -- 例如,不能跳轉(zhuǎn)到
for循環(huán)的中間或跳出finally子句。
-
l(ist)[first[, last]]? 列出當(dāng)前文件的源代碼。如果不帶參數(shù),則列出當(dāng)前行周圍的 11 行,或繼續(xù)前一個列表。如果用
.作為參數(shù),則列出當(dāng)前行周圍的 11 行。如果帶有一個參數(shù),則列出那一行周圍的 11 行。如果帶有兩個參數(shù),則列出所給的范圍中的代碼;如果第二個參數(shù)小于第一個參數(shù),則將其解釋為列出行數(shù)的計數(shù)。當(dāng)前幀中的當(dāng)前行用
->標(biāo)記。如果正在調(diào)試異常,且最早拋出或傳遞該異常的行不是當(dāng)前行,則那一行用>>標(biāo)記。3.2 新版功能:
>>標(biāo)記。
-
a(rgs)? 打印當(dāng)前函數(shù)的參數(shù)列表。
-
pexpression? 在當(dāng)前上下文中運行 expression 并打印它的值。
注解
print()也可以使用,但它不是一個調(diào)試器命令 --- 它執(zhí)行 Pythonprint()函數(shù)。
-
whatisexpression? 打印 expression 的類型。
-
sourceexpression? 嘗試獲取給定對象的源代碼并顯示出來。
3.2 新版功能.
-
display[expression]? 如果表達(dá)式的值發(fā)生改變則顯示它的值,每次將停止執(zhí)行當(dāng)前幀。
不帶表達(dá)式則列出當(dāng)前幀的所有顯示表達(dá)式。
3.2 新版功能.
-
undisplay[expression]? 不再顯示當(dāng)前幀中的表達(dá)式。 不帶表達(dá)式則清除當(dāng)前幀的所有顯示表達(dá)式。
3.2 新版功能.
-
alias[name [command]]? 創(chuàng)建一個標(biāo)識為 name 的別名來執(zhí)行 command。 執(zhí)行的命令 不可 加上引號。 可替換形參可通過
%1,%2等來標(biāo)示,而%*會被所有形參所替換。 如果沒有給出命令,則會顯示 name 的當(dāng)前別名。 如果沒有給出參數(shù),則會列出所有別名。別名允許嵌套并可包含能在 pdb 提示符下合法輸入的任何內(nèi)容。 請注意內(nèi)部 pdb 命令 可以 被別名所覆蓋。 這樣的命令將被隱藏直到別名被移除。 別名會遞歸地應(yīng)用到命令行的第一個單詞;行內(nèi)的其他單詞不會受影響。
作為示例,這里列出了兩個有用的別名(特別適合放在
.pdbrc文件中):# Print instance variables (usage "pi classInst") alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k]) # Print instance variables in self alias ps pi self
-
unaliasname? 刪除指定的別名。
-
!statement? 在當(dāng)前堆棧幀的上下文中執(zhí)行 (單行) statement。 感嘆號可以被省略,除非語句的第一個單詞與調(diào)試器命令重名。 要設(shè)置全局變量,你可以在同一行上為賦值命令添加前綴的
global語句,例如:(Pdb) global list_options; list_options = ['-l'] (Pdb)
-
run[args ...]? -
restart[args ...]? 重啟被調(diào)試的 Python 程序。 如果提供了參數(shù),它會用
shlex來拆分且拆分結(jié)果將被用作新的sys.argv。 歷史、中斷點、動作和調(diào)試器選項將被保留。restart是run的一個別名。
-
q(uit)? 退出調(diào)試器。 被執(zhí)行的程序?qū)⒈恢兄埂?/p>
-
debugcode? 進(jìn)入一個對代碼參數(shù)執(zhí)行步進(jìn)的遞歸調(diào)試器(該參數(shù)是在當(dāng)前環(huán)境中執(zhí)行的任意表達(dá)式或語句)。
-
retval? -
Print the return value for the last return of a function.
備注
- 1
一個幀是否會被認(rèn)為源自特定模塊是由幀全局變量
__name__來決定的。
