pdb --- Python的調(diào)試器?

源代碼: Lib/pdb.py


pdb 模塊定義了一個交互式源代碼調(diào)試器,用于 Python 程序。它支持在源碼行間設(shè)置(有條件的)斷點和單步執(zhí)行,檢視堆棧幀,列出源碼列表,以及在任何堆棧幀的上下文中運行任意 Python 代碼。它還支持事后調(diào)試,可以在程序控制下調(diào)用。

調(diào)試器是可擴展的——調(diào)試器實際被定義為 Pdb 類。該類目前沒有文檔,但通過閱讀源碼很容易理解它。擴展接口使用了 bdbcmd 模塊。

調(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,也可以使用 stepnext 逐步執(zhí)行語句(上述所有命令在后文有說明)。可選參數(shù) globalslocals 指定代碼執(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)試器類。

completekeystdinstdout 參數(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ù)。

run(statement, globals=None, locals=None)?
runeval(expression, globals=None, locals=None)?
runcall(function, *args, **kwds)?
set_trace()?

請參閱上文解釋同名函數(shù)的文檔。

調(diào)試器命令?

下方列出的是調(diào)試器可接受的命令。如下所示,大多數(shù)命令可以縮寫為一個或兩個字母。如 h(elp) 表示可以輸入 hhelp 來輸入幫助命令(但不能輸入 hehel,也不能是 HHelpHELP)。命令的參數(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)試器提示符下鍵入該文件。這對于別名很有用。若兩個文件都存在則首先讀取主目錄中的文件,且本地文件可以覆蓋其中定義的別名。

在 3.2 版更改: .pdbrc 現(xiàn)在可以包含繼續(xù)調(diào)試的命令,如 continuenext。文件中的這些命令以前是無效的。

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)的條件(如果有)。

tbreak [([filename:]lineno | function) [, condition]]?

臨時斷點,在第一次命中時會自動刪除。它的參數(shù)與 break 相同。

cl(ear) [filename:lineno | bpnumber [bpnumber ...]]?

如果參數(shù)是 filename:lineno,則清除此行上的所有斷點。如果參數(shù)是空格分隔的斷點編號列表,則清除這些斷點。如果不帶參數(shù),則清除所有斷點(但會先提示確認(rèn))。

disable [bpnumber [bpnumber ...]]?

禁用斷點,斷點以空格分隔的斷點編號列表給出。禁用斷點表示它不會導(dǎo)致程序停止執(zhí)行,但是與清除斷點不同,禁用的斷點將保留在斷點列表中并且可以(重新)啟用。

enable [bpnumber [bpnumber ...]]?

啟用指定的斷點。

ignore bpnumber [count]?

為指定的斷點編號設(shè)置忽略次數(shù)。如果省略 count,則忽略次數(shù)將設(shè)置為 0。忽略次數(shù)為 0 時斷點將變?yōu)榛顒訝顟B(tài)。如果為非零值,在每次達(dá)到斷點,且斷點未禁用,且關(guān)聯(lián)條件計算值為 true 的情況下,該忽略次數(shù)會遞減。

condition bpnumber [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è)置的斷點。

可以使用斷點命令來重新啟動程序。只需使用 continuestep 命令或其他可以恢復(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ù)返回為止。( nextstep 之間的區(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)記。

ll | longlist?

列出當(dāng)前函數(shù)或幀的所有源代碼。相關(guān)行的標(biāo)記與 list 相同。

3.2 新版功能.

a(rgs)?

打印當(dāng)前函數(shù)的參數(shù)列表。

p expression?

在當(dāng)前上下文中運行 expression 并打印它的值。

注解

print() 也可以使用,但它不是一個調(diào)試器命令 --- 它執(zhí)行 Python print() 函數(shù)。

pp expression?

p 命令類似,但表達(dá)式的值使用 pprint 模塊美觀地打印。

whatis expression?

打印 expression 的類型。

source expression?

嘗試獲取給定對象的源代碼并顯示出來。

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 新版功能.

interact?

啟動一個交互式解釋器(使用 code 模塊),它的全局命名空間將包含當(dāng)前作用域中的所有(全局和局部)名稱。

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
unalias name?

刪除指定的別名。

! 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)試器選項將被保留。 restartrun 的一個別名。

q(uit)?

退出調(diào)試器。 被執(zhí)行的程序?qū)⒈恢兄埂?/p>

debug code?

進(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__ 來決定的。