26.2. pdb — Python 调试器 — Python 文档

来自菜鸟教程
Python/docs/2.7/library/pdb
跳转至:导航、​搜索

26.2. 数据库 — Python 调试器

源代码: :source:`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)

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

python -m pdb myscript.py

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

2.4 版新功能: 添加了重新启动验尸行为。


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

import pdb; pdb.set_trace()

在您想要进入调试器的位置。 然后,您可以单步执行此语句后的代码,并使用 c 命令在没有调试器的情况下继续运行。

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

>>> 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)

该模块定义了以下功能; 每个进入调试器的方式略有不同:

pdb.run(statement[, globals[, locals]])
在调试器控制下执行 语句 (以字符串形式给出)。 在执行任何代码之前会出现调试器提示; 您可以设置断点并键入 continue,或者您可以使用 stepnext 单步执行语句(所有这些命令都在下面解释)。 可选的 globalslocals 参数指定执行代码的环境; 默认情况下使用模块 __main__ 的字典。 (参见 exec 语句或 eval() 内置函数的解释。)
pdb.runeval(expression[, globals[, locals]])
在调试器控制下计算 表达式 (以字符串形式给出)。 当 runeval() 返回时,它返回表达式的值。 否则这个函数类似于 run()
pdb.runcall(function[, argument, ...])
使用给定的参数调用 函数 (函数或方法对象,而不是字符串)。 当 runcall() 返回时,它返回函数调用返回的任何内容。 一旦输入函数,调试器提示就会出现。
pdb.set_trace()
在调用堆栈帧处进入调试器。 这对于在程序中的给定点硬编码断点很有用,即使代码没有被调试(例如 当断言失败时)。
pdb.post_mortem([traceback])
进入给定的 traceback 对象的事后调试。 如果没有给出 traceback,它使用当前正在处理的异常之一(如果要使用默认值,则必须处理异常)。
pdb.pm()
进入在 sys.last_traceback 中找到的回溯的事后调试。

run*函数和set_trace()是实例化Pdb类并调用同名方法的别名。 如果您想访问更多功能,您必须自己执行此操作:

class pdb.Pdb(completekey='tab', stdin=None, stdout=None, skip=None)

Pdb 是调试器类。

completekeystdinstdout 参数被传递给底层的 cmd.Cmd 类; 请参阅那里的说明。

skip 参数(如果给定)必须是全局样式模块名称模式的可迭代对象。 调试器不会进入源自与这些模式之一匹配的模块的帧。 1

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

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

2.7 版新功能:skip 参数。

run(statement[, globals[, locals]])
runeval(expression[, globals[, locals]])
runcall(function[, argument, ...])
set_trace()

有关上述功能,请参阅文档。


26.3. 调试器命令

调试器识别以下命令。 大多数命令可以缩写为一两个字母; 例如 h(elp) 表示可以使用 hhelp 输入帮助命令(但不能使用 hehel,也不能使用 HHelpHELP)。 命令的参数必须用空格(空格或制表符)分隔。 可选参数在命令语法中括在方括号 ([]) 中; 不得键入方括号。 命令语法中的替代项由竖线 (|) 分隔。

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

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

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

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

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

h(elp) [命令]

不带参数,打印可用命令列表。 使用 command 作为参数,打印有关该命令的帮助。 help pdb 显示完整的文档文件; 如果定义了环境变量 PAGER,则文件将通过该命令进行管道传输。 由于 command 参数必须是标识符,因此必须输入 help exec 以获取有关 ! 命令的帮助。

在哪里)

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

下)

将当前帧在堆栈跟踪中向下移动一级(到更新的帧)。

向上)

在堆栈跟踪中将当前帧向上移动一级(到较旧的帧)。

b(reak) [[filename:]lineno | 功能[, 条件]]

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

如果存在第二个参数,则它是一个表达式,该表达式必须在断点生效之前计算为真。

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

tbreak [[filename:]lineno | 功能[, 条件]]

临时断点,第一次命中时自动移除。 参数与 break 相同。

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

使用 filename:lineno 参数,清除该行的所有断点。 使用空格分隔的断点编号列表,清除这些断点。 没有争论,清除所有中断(但首先要求确认)。

禁用 [bpnumber [bpnumber …]]

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

启用 [bpnumber [bpnumber …]]

启用指定的断点。

忽略 bpnumber [count]

设置给定断点编号的忽略计数。 如果省略计数,则忽略计数设置为 0。 当忽略计数为零时,断点变为活动状态。 如果非零,则每次到达断点时计数都会递减,并且不会禁用断点,并且任何关联的条件评估为真。

条件bpnumber[条件]

条件是一个表达式,它必须在断点被遵守之前评估为真。 如果条件不存在,则删除任何现有条件; 即,断点是无条件的。

命令 [bpnumber]

为断点编号 bpnumber 指定命令列表。 命令本身出现在以下几行中。 键入仅包含“end”的行以终止命令。 一个例子:

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

要从断点中删除所有命令,请键入命令并紧随其后加上 end; 也就是说,不发出任何命令。

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

您可以使用断点命令再次启动您的程序。 只需使用 continue 命令、步骤或任何其他恢复执行的命令。

指定恢复执行的任何命令(当前 continue、step、next、return、jump、quit 及其缩写)将终止命令列表(就好像该命令紧跟在 end 之后)。 这是因为任何时候您恢复执行(即使是简单的下一步或步骤),您都可能遇到另一个断点——它可能有自己的命令列表,导致关于执行哪个列表的歧义。

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

2.5 版中的新功能。

步)

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

下一个)

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

直到)

继续执行,直到到达行号大于当前行的行或从当前帧返回时。

2.6 版中的新功能。

返回)

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

继续))

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

j(ump) lineno

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

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

l(ist) [first[, last]]

列出当前文件的源代码。 不带参数,在当前行周围列出 11 行或继续上一个列表。 使用一个参数,在该行周围列出 11 行。 使用两个参数,列出给定的范围; 如果第二个参数小于第一个参数,则将其解释为计数。

a(rgs)

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

p 表达式

在当前上下文中计算 表达式 并打印其值。

笔记

print 也可以使用,但不是调试器命令——它执行 Python print 语句。

pp 表达式

类似于 p 命令,除了表达式的值是使用 pprint 模块漂亮打印的。

别名 [ 名称 [命令]]

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

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

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

删除指定的别名。

[!]声明

在当前堆栈帧的上下文中执行(一行)语句。 感叹号可以省略,除非语句的第一个单词类似于调试器命令。 要设置全局变量,您可以在同一行中使用 global 命令作为赋值命令的前缀,例如:

(Pdb) global list_options; list_options = ['-l']
(Pdb)
运行 [args …]

重新启动已调试的 Python 程序。 如果提供了一个参数,它会被“shlex”分割,结果被用作新的 sys.argv。 历史记录、断点、操作和调试器选项被保留。 “重启”是“运行”的别名。

2.6 版中的新功能。

辞职)

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

脚注

1
帧是否被认为源自某个模块由帧全局变量中的 __name__ 决定。