最完整的Python pdb调试用法

pdbPython 的调试器

源代码: Lib/pdb.py


先来重点干货,常用命令 转自 https://juejin.cn/post/6844903847626801159
先简单介绍一下使用命令,这里不用记住,等用到的时候回来查就行。


1 进入命令行Debug模式,python -m pdb xxx.py


2 h:(help)帮助


3 w:(where)打印当前执行堆栈


4 d:(down)执行跳转到在当前堆栈的深一层(个人没觉得有什么用处)


5 u:(up)执行跳转到当前堆栈的上一层


6 b:(break)添加断点
       b 列出当前所有断点,和断点执行到统计次数

       b line_no:当前脚本的line_no行添加断点

       b filename:line_no:脚本filename的line_no行添加断点

       b function:在函数function的第一条可执行语句处添加断点
复制代码


7 tbreak:(temporary break)临时断点
       在第一次执行到这个断点之后,就自动删除这个断点,用法和b一样
复制代码


8 cl:(clear)清除断点
      cl 清除所有断点

      cl bpnumber1 bpnumber2... 清除断点号为bpnumber1,bpnumber2...的断点

      cl lineno 清除当前脚本lineno行的断点

      cl filename:line_no 清除脚本filename的line_no行的断点
复制代码


9 disable:停用断点,参数为bpnumber,和cl的区别是,断点依然存在,只是不启用


10 enable:激活断点,参数为bpnumber


11 s:(step)执行下一条命令
      如果本句是函数调用,则s会执行到函数的第一句
复制代码


12 n:(next)执行下一条语句
      如果本句是函数调用,则执行函数,接着执行当前执行语句的下一条。
复制代码


13 r:(return)执行当前运行函数到结束


14 c:(continue)继续执行,直到遇到下一条断点


15 l:(list)列出源码
       l 列出当前执行语句周围11条代码

       l first 列出first行周围11条代码

       l first second 列出first--second范围的代码,如果second<first,second将被解析为行数
复制代码


16 a:(args)列出当前执行函数的函数


17 p expression:(print)输出expression的值


18 pp expression:好看一点的p expression


19 run:重新启动debug,相当于restart


20 q:(quit)退出debug


21 j lineno:(jump)设置下条执行的语句函数
      只能在堆栈的最底层跳转,向后重新执行,向前可直接执行到行号
复制代码


22)unt:(until)执行到下一行(跳出循环),或者当前堆栈结束


23)condition bpnumber conditon,给断点设置条件,当参数condition返回True的时候bpnumber断点有效,否则bpnumber断点无效

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 模块实现的 Tab 补全可用于补全本模块的命令和命令的参数,例如,Tab 补全会提供当前的全局变量和局部变量,用作 p 命令的参数。

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

python3 -m pdb myscript.py

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

3.2 新版功能: pdb.py 现在接受 -c 选项,可以执行命令,这与将该命令写入 .pdbrc 文件相同,请参阅 调试器命令

3.7 新版功能: pdb.py 现在接受 -m 选项,该选项用于执行一个模块,类似于 python3 -m。与脚本相同,调试器将暂停在待执行模块第一行前。

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

import pdb; pdb.set_trace()

到你想进入调试器的位置。然后就可以单步执行上述语句之后的代码,要关闭调试器继续运行,请使用 continue 命令。

3.7 新版功能: 内置函数 breakpoint(),当以默认参数调用它时,可以用来代替 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)

本模块定义了下列函数,每个函数进入调试器的方式略有不同:

  • 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(***, header=None)

    在调用本函数的堆栈帧处进入调试器。用于硬编码一个断点到程序中的固定点处,即使该代码不在调试状态(如断言失败时)。如果传入 header,它将在调试开始前被打印到控制台。在 3.7 版更改: 仅关键字参数 header

  • pdb.``post_mortem(traceback=None)

    进入 traceback 对象的事后调试。如果没有给定 traceback,默认使用当前正在处理的异常之一(默认时,必须存在正在处理的异常)。

  • pdb.``pm()

    sys.last_traceback 中查找 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-style 样式的模块名称。如果遇到匹配上述样式的模块,调试器将不会进入来自该模块的堆栈帧。 1默认情况下,当发出 continue 命令时,Pdb 将为 SIGINT 信号设置一个处理程序(SIGINT 信号是用户在控制台按 Ctrl-C 时发出的)。这使用户可以按 Ctrl-C 再次进入调试器。如果希望 Pdb 不要修改 SIGINT 处理程序,请将 nosigint 设置为 true。readrc 参数默认为 true,它控制 Pdb 是否从文件系统加载 .pdbrc 文件。启用跟踪且带有 skip 参数的调用示范:import pdb; pdb.Pdb(skip=['django.*']).set_trace()引发一个 审计事件 pdb.Pdb,没有附带参数。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()请参阅上文解释同名函数的文档。

调试器命令

  (Pdb)a #查看全部栈内变量
  (Pdb)w 列出目前call stack 中的所在层。
  (Pdb)d 在call stack中往下移一层
  (Pdb)u 在call stack中往上移一层。如果在上移一层之后按下 n ,则会在上移之后的一层执行下一个叙述,之前的 function call 就自动返回。

下方列出的是调试器可接受的命令。如下所示,大多数命令可以缩写为一个或两个字母。如 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 级(默认为 1 级,移向更新的帧)。

  • u(p)`` [count]

    在堆栈回溯中,将当前帧向上移动 count 级(默认为 1 级,移向更老的帧)。

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

    如果带有 lineno 参数,则在当前文件相应行处设置一个断点。如果带有 function 参数,则在该函数的第一条可执行语句处设置一个断点。行号可以加上文件名和冒号作为前缀,以在另一个文件(可能是尚未加载的文件)中设置一个断点。另一个文件将在 sys.path 范围内搜索。请注意,每个断点都分配有一个编号,其他所有断点命令都引用该编号。如果第二个参数存在,它应该是一个表达式,且它的计算值为 true 时断点才起作用。如果不带参数执行,将列出所有中断,包括每个断点、命中该断点的次数、当前的忽略次数以及关联的条件(如果有)。

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

    临时断点,在第一次命中时会自动删除。它的参数与 break 相同。

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

    如果参数是 filename:lineno,则清除此行上的所有断点。如果参数是空格分隔的断点编号列表,则清除这些断点。如果不带参数,则清除所有断点(但会先提示确认)。

  • disable`` [bpnumber ...]

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

  • enable`` [bpnumber ...]

    启用指定的断点。

  • ignore`` bpnumber [count]

    为指定的断点编号设置忽略次数。如果省略 count,则忽略次数将设置为 0。忽略次数为 0 时断点将变为活动状态。如果为非零值,在每次达到断点,且断点未禁用,且关联条件计算值为 true 的情况下,该忽略次数会递减。

  • condition`` bpnumber [condition]

    为断点设置一个新 condition,它是一个表达式,且它的计算值为 true 时断点才起作用。如果没有给出 condition,则删除现有条件,也就是将断点设为无条件。

  • commands`` [bpnumber]

    为编号是 bpnumber 的断点指定一系列命令。命令内容将显示在后续的几行中。输入仅包含 end 的行来结束命令列表。举个例子:(Pdb) commands 1 (com) p some_variable (com) end (Pdb)要删除断点上的所有命令,请输入 commands 并立即以 end 结尾,也就是不指定任何命令。如果不带 bpnumber 参数,commands 作用于最后一个被设置的断点。可以为断点指定命令来重新启动程序。只需使用 continuestep 命令或其他可以继续运行程序的命令。如果指定了某个继续运行程序的命令(目前包括 continue, step, next, return, jump, quit 及它们的缩写)将终止命令列表(就像该命令后紧跟着 end)。因为在任何时候继续运行下去(即使是简单的 next 或 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。 执行的命令 不可 加上引号。 可替换形参可通过 %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

  • unalias`` name

    删除指定的别名。

  • !`` statement

    在当前堆栈帧的上下文中执行 (单行) statement。 感叹号可以被省略,除非语句的第一个单词与调试器命令重名。 要设置全局变量,你可以在同一行上为赋值命令添加前缀的 global 语句,例如:(Pdb) global list_options; list_options = ['-l'] (Pdb)

  • run`` [args ...]

  • restart`` [args ...]

    重启被调试的 Python 程序。 如果提供了参数,它会用 shlex 来拆分且拆分结果将被用作新的 sys.argv。 历史、中断点、动作和调试器选项将被保留。 restartrun 的一个别名。

  • q(uit)

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

  • debug`` code

    进入一个对代码参数执行步进的递归调试器(该参数是在当前环境中执行的任意表达式或语句)。

  • retval

    打印函数最后一次返回的返回值。

更详细的介绍可参考 10分钟教程掌握Python调试器pdb

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值