# `pdb` --- Python 的调试器

源代码： Lib/pdb.py

`pdb` 模块定义了一个交互式源代码调试器，用于 Python 程序。它支持在源码行间设置（有条件的）断点和单步执行，检视堆栈帧，列出源码列表，以及在任何堆栈帧的上下文中运行任意 Python 代码。它还支持事后调试，可以在程序控制下调用。

调试器是可扩展的——调试器实际被定义为 `Pdb` 类。该类目前没有文档，但通过阅读源码很容易理解它。扩展接口使用了 `bdb` 和 `cmd` 模块。

调试器的提示符是 `(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`，也可以使用 `step` 或 `next` 逐步执行语句（上述所有命令在后文有说明）。可选参数 globals 和 locals 指定代码执行环境，默认时使用 `__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` 是调试器类。

  completekey、stdin 和 stdout 参数都会传递给底层的 `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`()

    请参阅上文解释同名函数的文档。

## 调试器命令

下方列出的是调试器可接受的命令。如下所示，大多数命令可以缩写为一个或两个字母。如 `h(elp)` 表示可以输入 `h` 或 `help` 来输入帮助命令（但不能输入 `he` 或 `hel`，也不能是 `H` 或 `Help` 或 `HELP`）。命令的参数必须用空格（空格符或制表符）分隔。在命令语法中，可选参数括在方括号 (`[]`) 中，使用时请勿输入方括号。命令语法中的选择项由竖线 (`|`) 分隔。

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

调试器无法识别的命令将被认为是 Python 语句，并在正在调试的程序的上下文中执行。Python 语句也可以用感叹号 (`!`) 作为前缀。这是检查正在调试的程序的强大方法，甚至可以修改变量或调用函数。当此类语句发生异常，将打印异常名称，但调试器的状态不会改变。

调试器支持 别名。别名可以有参数，使得调试器对被检查的上下文有一定程度的适应性。

在一行中可以输入多个命令，以 `;;` 分隔。（不能使用单个 `;`，因为它用于分隔传递给 Python 解释器的一行中的多条语句。）切分命令很无脑，总是在第一个 `;;` 对处将输入切分开，即使它位于带引号的字符串之中。

如果文件 `.pdbrc` 存在于用户主目录或当前目录中，则将其读入并执行，等同于在调试器提示符下键入该文件。这对于别名很有用。若两个文件都存在则首先读取主目录中的文件，且本地文件可以覆盖其中定义的别名。

在 3.2 版更改: `.pdbrc` 现在可以包含继续调试的命令，如 `continue` 或 `next`。文件中的这些命令以前是无效的。

`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` 作用于最后一个被设置的断点。

  可以为断点指定命令来重新启动程序。只需使用 `continue` 或 `step` 命令或其他可以继续运行程序的命令。

  如果指定了某个继续运行程序的命令（目前包括 `continue`, `step`, `next`, `return`, `jump`, `quit` 及它们的缩写）将终止命令列表（就像该命令后紧跟着 end）。因为在任何时候继续运行下去（即使是简单的 next 或 step），都可能会遇到另一个断点，该断点可能具有自己的命令列表，这导致要执行的列表含糊不清。

  如果在命令列表中加入 'silent' 命令，那么在该断点处停下时就不会打印常规信息。如果希望断点打印特定信息后继续运行，这可能是理想的。如果没有其他命令来打印一些信息，则看不到已达到断点的迹象。

`s(tep)`

  运行当前行，在第一个可以停止的位置（在被调用的函数内部或在当前函数的下一行）停下。

`n(ext)`

  继续运行，直到运行到当前函数的下一行，或当前函数返回为止。（ `next` 和 `step` 之间的区别在于，`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`。 历史、中断点、动作和调试器选项将被保留。 `restart` 是 `run` 的一个别名。

`q(uit)`

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

`debug` `code`

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

`retval`

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

脚注

1

  一个帧是否会被认为源自特定模块是由帧全局变量 `__name__` 来决定的。