Skip to main content

27.3. pdb — Python调试器

源代码: Lib/pdb.py


模块 pdb 为Python程序定义了一个交互式源代码调试器。它支持在任何堆栈帧的上下文中设置(条件)断点和在源行级的单步,检查堆栈帧,源代码列表和评估任意Python代码。它还支持事后调试,并且可以在程序控制下调用。

调试器是可扩展的 - 它实际上被定义为类 Pdb。这是目前没有文件,但通过阅读源很容易理解。扩展接口使用模块 bdbcmd

调试器的提示符是 (Pdb)。在调试器的控制下运行程序的典型用法是:

>>> import pdb
>>> import mymodule
>>> pdb.run('mymodule.test()')
> <string>(0)?()
(Pdb) continue
> <string>(1)?()
(Pdb) continue
NameError: 'spam'
> <string>(1)?()
(Pdb)

在 3.3 版更改: 通过 readline 模块的制表完成可用于命令和命令参数,例如。当前全局和本地名称作为 p 命令的参数提供。

pdb.py 也可以作为脚本调用来调试其他脚本。例如:

python3 -m pdb myscript.py

当作为脚本调用时,如果被调试的程序异常退出,pdb将自动进入事后调试。经过死后调试(或正常退出程序后),pdb将重新启动程序。自动重新启动保留pdb的状态(例如断点),并且在大多数情况下比程序退出时退出调试器更有用。

3.2 新版功能: pdb.py 现在接受一个执行命令的 -c 选项,就像在 .pdbrc 文件中给出的一样,参见 调试器命令

从正在运行的程序中断入调试器的典型用法是插入

import pdb; pdb.set_trace()

在您想要打破调试器的位置。然后可以遍历此语句后的代码,并使用 continue 命令继续运行而不使用调试器。

检查崩溃程序的典型用法是:

>>> import pdb
>>> import mymodule
>>> mymodule.test()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  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)

模块定义了以下功能:每个以稍微不同的方式进入调试器:

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

在调试器控制下执行 statement (作为字符串或代码对象)。在任何代码执行之前出现调试器提示;您可以设置断点和类型 continue,或者您可以使用 stepnext 逐步执行该语句(所有这些命令如下所述)。可选的 globalslocals 参数指定执行代码的环境;默认情况下使用模块 __main__ 的字典。 (请参阅内置 exec()eval() 功能的说明。)

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

在调试器控制下评估 expression (作为字符串或代码对象)。当 runeval() 返回时,它返回表达式的值。否则,此函数类似于 run()

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

使用给定的参数调用 function (函数或方法对象,而不是字符串)。当 runcall() 返回时,它返回所返回的任何函数调用。一旦输入该函数,就会显示调试器提示。

pdb.set_trace()

在调用堆栈帧处输入调试器。这对于在程序中的给定点硬编码断点是有用的,即使代码没有被另外调试(例如当断言失败时)。

pdb.post_mortem(traceback=None)

输入给定 traceback 对象的事后调试。如果没有给出 traceback,它使用当前正在处理的异常(如果使用缺省值,则必须处理异常)。

pdb.pm()

输入 sys.last_traceback 中发现的追溯的事后调试。

run* 函数和 set_trace() 是用于实例化 Pdb 类和调用同名方法的别名。如果你想访问更多的功能,你必须自己这样做:

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

Pdb 是调试器类。

completekeystdinstdout 参数传递给基础 cmd.Cmd 类;看到那里的描述。

skip 参数,如果给定,必须是可迭代的glob样式模块名称模式。调试器不会步入到源于与这些模式之一匹配的模块中的帧。 [1]

默认情况下,当您给出 continue 命令时,Pdb会为SIGINT信号设置一个处理程序(当用户在控制台上按 Ctrl-C 时发送)。这允许您通过按 Ctrl-C 再次进入调试器。如果你想让Pdb不要触摸SIGINT处理程序,将 nosigint 设置为true。

readrc 参数默认为true,并控制Pdb是否从文件系统加载.pdbrc文件。

示例调用以使用 skip 启用跟踪:

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

3.1 新版功能: skip 参数。

3.2 新版功能: nosigint 参数。以前,Pdb从未设置SIGINT处理程序。

在 3.6 版更改: readrc 参数。

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

请参阅上述功能的文档。

27.3.1. 调试器命令

调试器识别的命令如下所示。大多数命令可以缩写为一个或两个字母,如图所示;例如 h(elp) 意味着 hhelp 可以用于输入帮助命令(但不能用于 hehel,也不能用于 HHelpHELP)。命令的参数必须由空格(空格或制表符)分隔。可选参数在命令语法中用方括号([])括起来;不得输入方括号。命令语法中的其他选项通过垂直条(|)分隔。

输入空行重复输入的最后一个命令。例外:如果最后一个命令是 list 命令,则会列出接下来的11行。

调试器不能识别的命令假定为Python语句,并在正在调试的程序的上下文中执行。 Python语句也可以带有感叹号(!)作为前缀。这是一个强大的方法来检查正在调试的程序;甚至可以改变变量或调用函数。当在此类语句中发生异常时,将打印异常名称,但调试器的状态不会更改。

调试器支持 别名。别名可以具有允许对检查的上下文具有一定水平的适应性的参数。

多个命令可以在单行上输入,由 ;; 分隔。 (不使用单个 ;,因为它是传递给Python解析器的行中的多个命令的分隔符。)没有智能用于分离命令;输入在第一个 ;; 对处拆分,即使它在带引号的字符串的中间。

如果文件 .pdbrc 存在于用户的主目录或当前目录中,则它将被读入并执行,就好像它在调试器提示符处键入。这对别名特别有用。如果两个文件都存在,那么首先读取主目录中的一个文件,并在其中定义的别名可以被本地文件覆盖。

在 3.2 版更改: .pdbrc 现在可以包含继续调试的命令,例如 continuenext。以前,这些命令没有效果。

h(elp) [command]

无参数时,打印可用命令的列表。使用 command 作为参数,打印有关该命令的帮助。 help pdb 显示完整的文档(pdb 模块的文档字符串)。由于 command 参数必须是标识符,因此必须输入 help exec 才能获得有关 ! 命令的帮助。

w(here)

打印堆栈跟踪,最新的帧在底部。箭头表示当前帧,它确定大多数命令的上下文。

d(own) [count]

将当前帧 count (默认一个)向下移动到堆栈跟踪(到更新的帧)。

u(p) [count]

将当前帧 count (默认值)移动到堆栈跟踪中(向较早的帧)。

b(reak) [([filename:]lineno | function) [, condition]]

使用 lineno 参数,在当前文件中设置断点。使用 function 参数,在该函数中的第一个可执行语句中设置断点。行号可以用文件名和冒号作为前缀,以在另一个文件(可能是尚未加载的文件)中指定断点。该文件在 sys.path 上搜索。请注意,每个断点都分配有一个数字,所有其他断点命令都引用该数字。

如果存在第二个参数,它是一个表达式,在断点被执行之前必须求值为true。

无参数,列出所有中断,包括每个断点,断点被击中的次数,当前忽略计数和相关条件(如果有)。

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

临时断点,当它第一次被击中时被自动删除。参数与 break 相同。

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

使用 filename:lineno 参数,清除此行上的所有断点。使用空格分隔的断点数列表,清除这些断点。没有论证,清除所有休息(但首先要求确认)。

disable [bpnumber [bpnumber ...]]

禁用以空格分隔的断点号列表形式给出的断点。禁用断点意味着它不能导致程序停止执行,但是与清除断点不同,它保留在断点列表中,并且可以(重新)启用。

enable [bpnumber [bpnumber ...]]

启用指定的断点。

ignore bpnumber [count]

设置给定断点号的忽略计数。如果忽略count,则忽略计数设置为0.当忽略计数为零时,断点变为活动状态。当非零时,每次达到断点时计数递减,并且不禁用断点,并且任何关联条件的计算结果为true。

condition bpnumber [condition]

为断点设置一个新的 condition,一个在断点被执行之前必须求值为true的表达式。如果 condition 不存在,则去除任何现有条件;即断点是无条件的。

commands [bpnumber]

指定断点号 bpnumber 的命令列表。命令本身显示在以下行。键入仅包含 end 的行以终止命令。一个例子:

(Pdb) commands 1
(com) p some_variable
(com) end
(Pdb)

要从断点中删除所有命令,请键入命令并立即使用 end;即,不给出命令。

没有 bpnumber 参数,命令引用最后一个断点集。

您可以使用断点命令重新启动您的程序。只需使用continue命令,或step,或任何其他恢复执行的命令。

指定任何恢复执行的命令(当前继续,步骤,下一步,返回,跳转,退出和它们的缩写)终止命令列表(就好像该命令紧接着结束)。这是因为任何时候你恢复执行(即使有一个简单的下一步或步骤),你可能会遇到另一个断点,它可能有自己的命令列表,导致执行列表的模糊。

如果在命令列表中使用“silent”命令,则不会打印关于在断点处停止的常见消息。这对于打印特定消息然后继续的断点可能是理想的。如果没有其他命令打印任何东西,您看不到到达断点的迹象。

s(tep)

执行当前行,在第一个可能的时间停止(在调用的函数中或当前函数中的下一行)。

n(ext)

继续执行,直到到达当前函数中的下一行或返回。 (nextstep 之间的区别是 step 在被调用的函数内停止,而 next 以(几乎)全速执行被调用的函数,只在当前函数中的下一行停止。)

unt(il) [lineno]

如果没有参数,继续执行直到到达具有大于当前数字的数字的行。

使用行号,继续执行,直到到达具有大于或等于的数字的行。在这两种情况下,当当前帧返回时也停止。

在 3.2 版更改: 允许给出明确的行号。

r(eturn)

继续执行直到当前函数返回。

c(ont(inue))

继续执行,只有在遇到断点时停止。

j(ump) lineno

设置将要执行的下一行。仅在最下面的框架中可用。这使您可以跳回并再次执行代码,或者向前跳转以跳过您不想运行的代码。

应当注意,不是所有的跳转都被允许 - 例如,不可能跳到 for 循环的中间或者跳出 finally 子句。

l(ist) [first[, last]]

列出当前文件的源代码。如果没有参数,请列出当前行周围的11行或继续上一个列表。使用 . 作为参数,列出当前行周围的11行。使用一个参数,在该行列出11行。有两个参数,列出给定的范围;如果第二个参数小于第一个,它被解释为计数。

当前帧中的当前行由 -> 指示。如果正在调试异常,则异常最初引发或传播的行由 >> 指示,如果它与当前行不同。

3.2 新版功能: >> 标记。

ll | longlist

列出当前函数或框架的所有源代码。有趣的线标记为 list

3.2 新版功能.

a(rgs)

打印当前函数的参数列表。

p expression

在当前上下文中评估 expression 并打印其值。

注解

print() 也可以使用,但不是调试器命令—这执行Python print() 函数。

pp expression

p 命令一样,除了表达式的值是使用 pprint 模块打印的。

whatis expression

打印 expression 的类型。

source expression

尝试获取给定对象的源代码并显示它。

3.2 新版功能.

display [expression]

如果表达式更改,则每次在当前帧中停止执行时,显示表达式的值。

不带表达式时,列出当前帧的所有显示表达式。

3.2 新版功能.

undisplay [expression]

不要在当前框架中再显示表达式。如果没有表达式,请清除当前帧的所有显示表达式。

3.2 新版功能.

interact

启动一个交互式解释器(使用 code 模块),其全局命名空间包含在当前作用域中找到的所有(全局和局部)名称。

3.2 新版功能.

alias [name [command]]

创建一个名为 name 的执行 command 的别名。命令必须将 not 括在引号中。可替换参数可以由 %1%2 等指示,而 %* 由所有参数替换。如果没有给出命令,则显示 name 的当前别名。如果没有给出参数,则列出所有别名。

别名可以嵌套,并且可以包含可以在pdb提示符下合法输入的任何内容。注意,内部pdb命令 can 被别名覆盖。然后隐藏这样的命令,直到去除别名。别名被递归地应用于命令行的第一个字;所有其他单词在一行留下。

例如,这里有两个有用的别名(尤其是放在 .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

在当前堆栈帧的上下文中执行(单行) statement。除非语句的第一个单词类似于调试器命令,否则可以省略感叹号。要设置全局变量,您可以在分配命令前面加上 global 语句在同一行,例如。:

(Pdb) global list_options; list_options = ['-l']
(Pdb)
run [args ...]
restart [args ...]

重新启动调试的Python程序。如果提供了参数,则使用 shlex 进行分割,并将结果用作新的 sys.argv。历史,断点,动作和调试器选项被保留。 restartrun 的别名。

q(uit)

从调试器中退出。正在执行的程序中止。

脚注

[1]

帧是否被认为源于某个模块由 __name__ 在帧全局中确定。