pdb --- Python 偵錯器

原始碼:Lib/pdb.py


pdb 模組定義了一個 Python 程式的互動式原始碼偵錯器。它支援在原始碼列層級 (source line level) 設定(條件式的)斷點 (breakpoint) 和單步執行、檢視 stack frame(堆疊框)、列出原始碼、以及在任何 stack frame 情境 (context) 中為任意 Python 程式碼求值 (evaluation)。它還支援事後偵錯 (post-mortem debugging),並可以在程式控制下呼叫。

偵錯器是可擴充的 —— 偵錯器實際被定義為 Pdb 類別。該類別目前沒有文件,但可以很容易地透過閱讀原始碼來理解它。擴充套件介面使用了 bdbcmd 模組。

也參考

faulthandler 模組

用於在出現故障時、超時 (timeout) 後或於接收到使用者訊號時,顯式地轉儲 (dump) Python 回溯 (traceback)。

traceback 模組

用於提取、格式化和印出 Python 程式 stack trace(堆疊追蹤)的標準介面。

自一個執行中程式切入偵錯器的典型用法為插入:

import pdb; pdb.set_trace()

或:

breakpoint()

到你想切入偵錯器的位置,然後執行程式,就可以單步執行上述陳述式之後的程式碼,並可以使用 continue 命令來離開偵錯器、繼續執行。

在 3.7 版的變更: 當使用預設值呼叫時,可以使用內建的 breakpoint() 來取代 import pdb; pdb.set_trace()

def double(x):
   breakpoint()
   return x * 2
val = 3
print(f"{val} * 2 is {double(val)}")

偵錯器的提示字元是 (Pdb),這表示你處於偵錯模式:

> ...(2)double()
-> breakpoint()
(Pdb) p x
3
(Pdb) continue
3 * 2 is 6

在 3.3 版的變更: 透過 readline 模組達成的 tab 補全可用於補全本模組的命令和命令的引數,例如會提供目前的全域和區域名稱以作為 p 命令的引數。

命令列介面

你還可以從命令列叫用 pdb 來偵錯其他腳本。例如:

python -m pdb [-c command] (-m module | -p pid | pyfile) [args ...]

當作為模組叫用時,如果被偵錯的程序不正常地退出,pdb 將自動進入事後偵錯。事後偵錯後(或程式正常退出後),pdb 將重新啟動程式。自動重新啟動會保留 pdb 的狀態(例如斷點),並且在大多數情況下比在程式退出時退出偵錯器更有用。

-c, --command <command>

就像在 .pdbrc 檔案中給定的那樣來執行命令;請參閱偵錯器命令

在 3.2 版的變更: 新增了 -c 選項。

-m <module>

以類似於 python -m 的方式來執行模組。與腳本一樣,偵錯器將在模組的第一列之前暫停執行。

在 3.7 版的變更: 新增了 -m 選項。

-p, --pid <pid>

Attach to the process with the specified PID.

在 3.14 版被加入.

To attach to a running Python process for remote debugging, use the -p or --pid option with the target process's PID:

python -m pdb -p 1234

備註

Attaching to a process that is blocked in a system call or waiting for I/O will only work once the next bytecode instruction is executed or when the process receives a signal.

在偵錯器控制下執行陳述式的典型用法是:

>>> import pdb
>>> def f(x):
...     print(1 / x)
>>> pdb.run("f(2)")
> <string>(1)<module>()
(Pdb) continue
0.5
>>>

檢查一個損壞程式的典型用法:

>>> import pdb
>>> def f(x):
...     print(1 / x)
...
>>> f(0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f
ZeroDivisionError: division by zero
>>> pdb.pm()
> <stdin>(2)f()
(Pdb) p x
0
(Pdb)

在 3.13 版的變更: PEP 667 的實作意味著透過 pdb 進行的名稱賦予 (name assignments) 會立即影響有效作用域,即使在最佳化作用域內運作也是如此。

本模組定義了下列函式,每個函式進入偵錯器的方式略有不同:

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

在偵錯器控制下執行 statement(以字串或程式碼物件形式給定)。偵錯提示字元會在執行任何程式碼前出現;你可以設定斷點並輸入 continue,或也可以使用 stepnext 逐步執行陳述式(這些命令在下面都有說明)。可選引數 globalslocals 指定程式碼執行的環境;預設使用 __main__ 模組的字典。(請參閱內建函式 exec()eval() 的說明。)

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

在偵錯器控制下為 expression 求值(以字串或程式碼物件形式給定)。當 runeval() 回傳時,它回傳 expression 的值。除此之外,該函式與 run() 類似。

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

使用給定的引數呼叫 function(只可以是函式或方法物件,不能是字串)。runcall() 回傳的是所呼叫函式的回傳值。偵錯器提示字元將在進入函式後立即出現。

pdb.set_trace(*, header=None, commands=None)

在呼叫此函式的 stack frame 進入偵錯器。用於在程式中給定之處寫死 (hard-code) 一個斷點,即便該程式碼不在偵錯狀態(如斷言失敗時)。如有給定 header,它將在偵錯正要開始前被印出到控制台。如果給定了 commands 引數,它會是在偵錯器啟動時要執行的命令清單。

在 3.7 版的變更: 僅限關鍵字引數 header

在 3.13 版的變更: set_trace() 將立即進入偵錯器,而不是在下一列要執行的程式碼中。

在 3.14 版被加入: commands 引數。

awaitable pdb.set_trace_async(*, header=None, commands=None)

async version of set_trace(). This function should be used inside an async function with await.

async def f():
    await pdb.set_trace_async()

await statements are supported if the debugger is invoked by this function.

在 3.14 版被加入.

pdb.post_mortem(t=None)

進入所給定例外或回溯物件的事後偵錯。如果沒有給定,預設使用目前正在處理的例外,或如果沒有例外則會引發 ValueError

在 3.13 版的變更: 新增對例外物件的支援。

pdb.pm()

進入在 sys.last_exc 中發現的例外的事後偵錯。

pdb.set_default_backend(backend)

There are two supported backends for pdb: 'settrace' and 'monitoring'. See bdb.Bdb for details. The user can set the default backend to use if none is specified when instantiating Pdb. If no backend is specified, the default is 'settrace'.

備註

breakpoint() and set_trace() will not be affected by this function. They always use 'monitoring' backend.

在 3.14 版被加入.

pdb.get_default_backend()

Returns the default backend for pdb.

在 3.14 版被加入.

run* 函式和 set_trace() 都是別名,用於實例化 (instantiate) Pdb 類別並呼叫同名方法。如果要使用更多功能,則必須自己執行以下操作:

class pdb.Pdb(completekey='tab', stdin=None, stdout=None, skip=None, nosigint=False, readrc=True, mode=None, backend=None, colorize=False)

Pdb 是偵錯器類別。

completekeystdinstdout 引數會被傳到底層的 cmd.Cmd 類別;請於該文件閱讀相關敘述。

如果給定 skip 引數,則它必須是一個給出 glob 樣式之模組名稱的疊代器。如果遇到匹配這些樣式的模組,偵錯器將不會進入來自該模組的 frame。 [1]

預設情況下,當你發出 continue 命令時,Pdb 會為 SIGINT 訊號(即使用者在控制台上按下 Ctrl-C 時會發送的訊號)設定一個處理程式 (handler),這允許你透過按下 Ctrl-C 再次切入偵錯器。如果你希望 Pdb 不影響到 SIGINT 處理程式,請將 nosigint 設定為 true。

readrc 引數預設為 true,它控制 Pdb 是否從檔案系統載入 .pdbrc 檔案。

The mode argument specifies how the debugger was invoked. It impacts the workings of some debugger commands. Valid values are 'inline' (used by the breakpoint() builtin), 'cli' (used by the command line invocation) or None (for backwards compatible behaviour, as before the mode argument was added).

The backend argument specifies the backend to use for the debugger. If None is passed, the default backend will be used. See set_default_backend(). Otherwise the supported backends are 'settrace' and 'monitoring'.

The colorize argument, if set to True, will enable colorized output in the debugger, if color is supported. This will highlight source code displayed in pdb.

啟用追蹤 (tracing) 且帶有 skip 引數的呼叫示範:

import pdb; pdb.Pdb(skip=['django.*']).set_trace()

不帶引數地引發一個稽核事件 (auditing event) pdb.Pdb

在 3.1 版的變更: 新增了 skip 參數。

在 3.2 版的變更: 新增了 nosigint 參數。以前 SIGINT 處理程式從未被 Pdb 設定過。

在 3.6 版的變更: readrc 引數。

在 3.14 版被加入: 新增了 mode 引數。

在 3.14 版被加入: 新增了 backend 引數。

在 3.14 版被加入: 新增了 colorize 引數。

在 3.14 版的變更: Inline breakpoints like breakpoint() or pdb.set_trace() will always stop the program at calling frame, ignoring the skip pattern (if any).

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

請見上面關於這些函式的文件說明。

偵錯器命令

下方列出的是偵錯器能認得的命令。如下所示,大多數命令可以縮寫為一個或兩個字母。如 h(elp) 表示可以輸入 hhelp 來輸入幫助命令(但不能輸入 hehel,也不能是 HHelpHELP)。命令的引數必須用空格(空格符 (spaces) 或製表符 (tabs))分隔。在命令語法中,可選引數被括在方括號 ([]) 中;使用時請勿輸入方括號。命令語法中的選擇項由豎線 (|) 分隔。

輸入一個空白列 (blank line) 將重複上次輸入的命令。例外:如果上一個命令是 list 命令,則會列出接下來的 11 列。

偵錯器無法識別的命令將被認為是 Python 陳述式,並以正在偵錯的程式之情境來執行。Python 陳述式也可以用驚嘆號 (!) 作為前綴,這是檢視正在偵錯之程式的強大方法,甚至可以修改變數或呼叫函式。當此類陳述式發生例外,將印出例外名稱,但偵錯器的狀態不會改變。

在 3.13 版的變更: 現在可以正確辨識並執行前綴為 pdb 命令的運算式/陳述式。

偵錯器有支援設定別名。別名可以有參數,使得偵錯器對被檢查的情境有一定程度的適應性。

在一列中可以輸入多個以 ;; 分隔的命令。(不能使用單個 ;,因為它用於分隔傳遞給 Python 剖析器一列中的多個命令。)切分命令沒運用什麼高深的方式;輸入總是在第一處 ;; 被切分開,即使它位於引號內的字串之中。對於具有雙分號字串的一個變通解法,是使用隱式字串連接 ';'';'";"";"

要設定臨時全域變數,請使用便利變數 (convenience variable)便利變數是名稱以 $ 開頭的變數。例如 $foo = 1 會設定一個全域變數 $foo,你可以在偵錯器會話 (debugger session) 中使用它。當程式恢復執行時,便利變數將被清除,因此與使用 foo