pdb
— Python 调试器¶
源代码: Lib/pdb.py
模块 pdb
为 Python 程序定义了一个交互式源代码调试器。它支持设置(条件)断点和在源代码行级别单步执行,检查堆栈帧,源代码列表以及在任何堆栈帧的上下文中评估任意 Python 代码。它还支持事后调试,并且可以在程序控制下调用。
调试器是可扩展的 - 它实际上被定义为类 Pdb
。这目前没有记录,但通过阅读源代码很容易理解。扩展接口使用模块 bdb
和 cmd
.
另请参阅
- 模块
faulthandler
用于在故障时,超时后或在用户信号后显式转储 Python 追踪。
- 模块
traceback
用于提取,格式化和打印 Python 程序的堆栈追踪的标准接口。
典型的进入调试器的用法是插入
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)
,它表示您处于调试模式
> ...(3)double()
-> return x * 2
(Pdb) p x
3
(Pdb) continue
3 * 2 is 6
版本 3.3 中的变更: 通过 readline
模块提供的制表符补全可用于命令和命令参数,例如,当前的全局和局部名称将作为 p
命令的参数提供。
您还可以从命令行调用 pdb
来调试其他脚本。例如
python -m pdb myscript.py
当作为模块调用时,如果被调试的程序异常退出,pdb 将自动进入事后调试。在事后调试之后(或程序正常退出之后),pdb 将重新启动程序。自动重启保留了 pdb 的状态(例如断点),并且在大多数情况下比程序退出时退出调试器更有用。
版本 3.2 中的变更: 添加了 -c
选项,以执行命令,就好像它们是在 .pdbrc
文件中给出的一样;请参阅 调试器命令.
版本 3.7 中的变更: 添加了 -m
选项,以类似于 python -m
的方式执行模块。与脚本一样,调试器将在模块的第一行之前暂停执行。
在调试器控制下执行语句的典型用法是
>>> 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)
该模块定义了以下函数;每个函数都以稍微不同的方式进入调试器
- pdb.run(statement, globals=None, locals=None)¶
在调试器控制下执行 statement(以字符串或代码对象的形式给出)。在执行任何代码之前,调试器提示符将出现;您可以设置断点并键入
continue
,或者您可以使用step
或next
逐步执行语句(所有这些命令将在下面解释)。可选的 globals 和 locals 参数指定执行代码的环境;默认情况下,使用模块__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)¶
在调用堆栈帧中进入调试器。这对于在程序中的给定点硬编码断点很有用,即使代码没有被调试(例如,当断言失败时)。如果给出,header 将在调试开始之前打印到控制台。
版本 3.7 中的变更: 仅限关键字的参数 header。
- pdb.post_mortem(traceback=None)¶
进入给定traceback对象的后期调试。如果没有给出traceback,它将使用当前正在处理的异常的traceback(如果要使用默认值,则必须正在处理异常)。
- pdb.pm()¶
进入在
sys.last_traceback
中找到的traceback的后期调试。
The run*
functions and set_trace()
are aliases for instantiating the Pdb
class and calling the method of the same name. If you want to access further features, you have to do this yourself
- class pdb.Pdb(completekey='tab', stdin=None, stdout=None, skip=None, nosigint=False, readrc=True)¶
Pdb
是调试器类。The completekey, stdin and stdout arguments are passed to the underlying
cmd.Cmd
class; see the description there.如果给出skip参数,它必须是 glob 样式模块名称模式的可迭代对象。调试器不会进入源自与这些模式之一匹配的模块的帧。 [1]
默认情况下,当您发出
continue
命令时,Pdb 会为 SIGINT 信号(当用户在控制台上按下 Ctrl-C 时发送)设置一个处理程序。这允许您通过按下 Ctrl-C 再次进入调试器。如果您希望 Pdb 不触碰 SIGINT 处理程序,请将nosigint 设置为 true。The readrc argument defaults to true and controls whether Pdb will load .pdbrc files from the filesystem.
使用skip启用跟踪的示例调用
import pdb; pdb.Pdb(skip=['django.*']).set_trace()
引发一个没有参数的 审计事件
pdb.Pdb
。在版本 3.1 中更改: 添加了skip参数。
在版本 3.2 中更改: 添加了nosigint参数。以前,Pdb 从未设置 SIGINT 处理程序。
在版本 3.6 中更改: The readrc argument.
调试器命令¶
调试器识别的命令列在下面。大多数命令可以缩写为一个或两个字母,如所示;例如,h(elp)
表示可以使用 h
或 help
进入帮助命令(但不能使用 he
或 hel
,也不能使用 H
或 Help
或 HELP
)。命令的参数必须用空格(空格或制表符)分隔。可选参数在命令语法中用方括号 ([]
) 括起来;方括号不能输入。命令语法中的备选方案用竖线 (|
) 分隔。
输入空行将重复最后输入的命令。例外:如果最后一个命令是 list
命令,则将列出接下来的 11 行。
调试器无法识别的命令被假定为 Python 语句,并在被调试程序的上下文中执行。Python 语句也可以用感叹号 (!
) 作为前缀。这是一种检查被调试程序的强大方法;甚至可以更改变量或调用函数。当在这样的语句中发生异常时,会打印异常名称,但调试器的状态不会改变。
调试器支持 别名。别名可以有参数,这允许人们在一定程度上适应正在检查的上下文。
多条命令可以输入到单行上,用 ;;
分隔。(单个 ;
不使用,因为它是在传递给 Python 解析器的行中用于分隔多条命令的分隔符。)不会对分隔命令应用任何智能;输入在第一个 ;;
对处分割,即使它在引号字符串的中间。对于包含双分号的字符串,一种解决方法是使用隐式字符串连接 ';'';'
或 ";"";"
。
要设置一个临时的全局变量,请使用便利变量。便利变量是一个名称以 $
开头的变量。例如,$foo = 1
设置一个全局变量 $foo
,您可以在调试器会话中使用它。当程序恢复执行时,便利变量会被清除,因此与使用像 foo = 1
这样的普通变量相比,它不太可能干扰您的程序。
有三个预设的便利变量
$_frame
: 您正在调试的当前帧$_retval
: 如果帧正在返回,则为返回值$_exception
: 如果帧正在引发异常,则为异常
版本 3.12 中新增: 添加了便利变量功能。
如果用户主目录或当前目录中存在文件 .pdbrc
,则使用 'utf-8'
编码读取该文件,并像在调试器提示符处键入一样执行它,但空行和以 #
开头的行除外。这对于别名特别有用。如果两个文件都存在,则首先读取主目录中的文件,并且在本地文件中可以覆盖在那里定义的别名。
版本 3.11 中更改: .pdbrc
现在使用 'utf-8'
编码读取。以前,它使用系统区域设置编码读取。
- 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
上搜索文件。请注意,每个断点都分配了一个数字,所有其他断点命令都引用该数字。如果存在第二个参数,则它是一个表达式,该表达式必须在断点生效之前计算为真。
没有参数,列出所有断点,包括每个断点的命中次数、当前忽略计数以及任何关联的条件。
- cl(ear) [filename:lineno | bpnumber ...]¶
使用filename:lineno参数,清除此行上的所有断点。使用以空格分隔的断点编号列表,清除这些断点。没有参数,清除所有断点(但首先询问确认)。
- disable bpnumber [bpnumber ...]¶
禁用以空格分隔的断点编号列表给出的断点。禁用断点意味着它不能导致程序停止执行,但与清除断点不同,它保留在断点列表中,可以(重新)启用。
- enable bpnumber [bpnumber ...]¶
启用指定的断点。
- ignore bpnumber [count]¶
设置给定断点编号的忽略计数。如果省略count,则忽略计数设置为 0。当忽略计数为零时,断点变为活动状态。当非零时,每次断点到达时,count 都会递减,并且断点不会被禁用,并且任何关联的条件都会计算为真。
- condition bpnumber [condition]¶
为断点设置一个新的condition,一个表达式,该表达式必须在断点生效之前计算为真。如果condition不存在,则会删除任何现有的条件;即断点变为无条件的。
- commands [bpnumber]¶
为断点编号bpnumber指定命令列表。命令本身出现在接下来的行中。键入仅包含
end
的一行以终止命令。一个例子(Pdb) commands 1 (com) p some_variable (com) end (Pdb)
要从断点中删除所有命令,请键入
commands
,然后立即键入end
;也就是说,不给出任何命令。如果没有bpnumber参数,则
commands
指的是最后设置的断点。您可以使用断点命令重新启动程序。只需使用
continue
命令,或step
,或任何其他恢复执行的命令。指定任何恢复执行的命令(目前包括
continue
、step
、next
、return
、jump
、quit
以及它们的缩写)都会终止命令列表(就像该命令后面紧跟着 end 一样)。这是因为,无论何时恢复执行(即使是简单的 next 或 step),你都可能遇到另一个断点,而该断点可能拥有自己的命令列表,从而导致关于执行哪个列表的歧义。如果在命令列表中使用
silent
命令,则不会打印关于在断点处停止的通常消息。这对于那些需要打印特定消息然后继续的断点来说可能是有益的。如果其他命令都没有打印任何内容,你将看不到任何迹象表明断点已被触及。
- s(tep)¶
执行当前行,在第一个可能的机会停止(在被调用的函数中或在当前函数的下一行)。
- n(ext)¶
继续执行,直到到达当前函数中的下一行或它返回。(
next
和step
之间的区别在于,step
会在被调用的函数内部停止,而next
会以(几乎)全速执行被调用的函数,只在当前函数的下一行停止。)
- unt(il) [lineno]¶
没有参数,继续执行,直到到达行号大于当前行的行。
带有 lineno,继续执行,直到到达行号大于或等于 lineno 的行。在这两种情况下,当当前帧返回时也会停止。
在版本 3.2 中更改: 允许给出明确的行号。
- r(eturn)¶
继续执行,直到当前函数返回。
- c(ont(inue))¶
继续执行,只在遇到断点时停止。
- j(ump) lineno¶
设置将要执行的下一行。仅在最底层的帧中可用。这使你能够跳回并再次执行代码,或跳过不想运行的代码。
- l(ist) [first[, last]]¶
列出当前文件的源代码。没有参数,列出当前行周围的 11 行,或继续之前的列表。带有
.
作为参数,列出当前行周围的 11 行。带有单个参数,列出该行周围的 11 行。带有两个参数,列出给定的范围;如果第二个参数小于第一个参数,则将其解释为计数。当前帧中的当前行由
->
表示。如果正在调试异常,则在异常最初引发或传播的行上用>>
表示,如果它与当前行不同。在版本 3.2 中更改: 添加了
>>
标记。
- a(rgs)¶
打印当前函数的参数及其当前值。
- whatis expression¶
打印 expression 的类型。
- source expression¶
尝试获取 expression 的源代码并显示它。
在版本 3.2 中添加。
- display [expression]¶
每次在当前帧中停止执行时,如果 expression 的值发生了变化,则显示它的值。
没有 expression,列出当前帧的所有显示表达式。
注意
Display 会评估 expression 并将其与 expression 的先前评估结果进行比较,因此当结果是可变的时,Display 可能无法识别变化。
示例
lst = [] breakpoint() pass lst.append(1) print(lst)
Display 不会意识到
lst
已经改变,因为评估结果在与先前结果进行比较之前,被lst.append(1)
就地修改了> example.py(3)<module>() -> pass (Pdb) display lst display lst: [] (Pdb) n > example.py(4)<module>() -> lst.append(1) (Pdb) n > example.py(5)<module>() -> print(lst) (Pdb)
你可以使用一些复制机制技巧来使其正常工作
> example.py(3)<module>() -> pass (Pdb) display lst[:] display lst[:]: [] (Pdb) n > example.py(4)<module>() -> lst.append(1) (Pdb) n > example.py(5)<module>() -> print(lst) display lst[:]: [1] [old: []] (Pdb)
在版本 3.2 中添加。
- undisplay [expression]¶
不再在当前帧中显示 expression。没有 expression,清除当前帧的所有显示表达式。
在版本 3.2 中添加。
- alias [name [command]]¶
创建一个名为 name 的别名,它执行 command。command 不能用引号括起来。可替换的参数可以用
%1
、%2
等表示,而%*
被所有参数替换。如果省略 command,则显示 name 的当前别名。如果没有给出参数,则列出所有别名。别名可以嵌套,并且可以包含在 pdb 提示符处可以合法键入的任何内容。请注意,内部 pdb 命令可以被别名覆盖。这样的命令将被隐藏,直到别名被删除。别名会递归地应用于命令行的第一个词;命令行中的所有其他词都会被保留。
例如,以下两个别名很有用(尤其是在
.pdbrc
文件中):# Print instance variables (usage "pi classInst") alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}") # Print instance variables in self alias ps pi self
- unalias name¶
删除指定的别名 name。
- ! statement¶
在当前堆栈帧的上下文中执行(单行)statement。除非语句的第一个词类似于调试器命令,否则可以省略感叹号,例如:
(Pdb) ! n=42 (Pdb)
要设置全局变量,可以在同一行上用
global
语句作为前缀,例如:(Pdb) global list_options; list_options = ['-l'] (Pdb)
- run [args ...]¶
- restart [args ...]¶
重新启动调试的 Python 程序。如果提供了 *args*,它将使用
shlex
拆分,结果将用作新的sys.argv
。历史记录、断点、操作和调试器选项将被保留。restart
是run
的别名。
- q(uit)¶
退出调试器。正在执行的程序将被中止。
- debug code¶
进入递归调试器,它将逐步执行 *code*(它是在当前环境中执行的任意表达式或语句)。
- retval¶
打印当前函数最后一次返回的返回值。
脚注