# 27.3. `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自动补全，例如当前全局和局部名称作为`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`，也可以使用`step`或`next`逐步执行该语句（所有这些命令将在下面说明）。可选的全局变量和局部变量参数指定执行代码的环境；默认使用模块的字典`__main__`。（请参阅内建`exec()`或`eval()`函数的解释。）

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

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

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

  使用给定的参数调用函数（函数或方法对象，而不是字符串）。当`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)

  `Pdb`是调试器类。

  completekey，stdin和stdout参数传递给底层的`cmd.Cmd`看到那里的描述。

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

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

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

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

  版本3.1中的新功能： 跳过参数。

  版本3.2中的新功能： nosigint参数。以前，一个SIGINT处理程序从来没有被Pdb设置。

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

    请参阅上述功能的文档。

## 27.3.1. Debugger Commands

调试器识别的命令如下所示。大多数命令可以缩写为一个或两个字母，如图所示；例如 `h(elp)` means that either `h` or `help` can be used to enter the help command (but not `he` or `hel`, nor `H` or `Help` or `HELP`). 命令的参数必须由空格（空格或制表符）分隔。可选参数在命令语法中用方括号（`[]`）括起来；不得输入方括号。命令语法中的其他选项通过垂直条（`|`）分隔。

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

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

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

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

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

在版本3.2中更改： `.pdbrc`现在可以包含继续调试的命令，例如`continue`或`next`。以前，这些命令没有效果。

`h(elp)``[command]`

  无参数时，打印可用命令的列表。使用命令作为参数，打印有关该命令的帮助。`help pdb`显示完整文档（`pdb`模块的文档字符串）。Since the command argument must be an identifier, `help exec` must be entered to get help on the `!`命令。

`w(here)`

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

`d(own)``[count]`

  将当前帧计数（默认一个）向下移动到堆栈跟踪（更新的帧）。

`u(p)``[count]`

  将当前帧计数（默认值）移动到堆栈跟踪（到较早的帧）。

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

  使用lineno参数，在当前文件中设置断点。使用函数参数，在该函数中的第一个可执行语句中设置断点。行号可以用文件名和冒号作为前缀，以在另一个文件（可能是尚未加载的文件）中指定断点。在`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]`

  为断点设置新的条件，这是在断点被执行之前必须计算为true的表达式。如果条件不存在，则删除任何现有条件；即断点是无条件的。

`commands``[bpnumber]`

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

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

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

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

  您可以使用断点命令重新启动程序。只需使用continue命令，或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`

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

  注意

  `print()`也可以使用，但不是调试器命令 - 这将执行Python `print()`函数。

`pp` `expression`

  像`p`命令，除了表达式的值是使用`pprint`模块打印的。

`whatis` `expression`

  打印表达式的类型。

`source` `expression`

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

  版本3.2中的新功能。

`display``[expression]`

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

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

  版本3.2中的新功能。

`undisplay``[expression]`

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

  版本3.2中的新功能。

`interact`

  启动一个交互式解释器（使用`code`模块），其全局命名空间包含当前范围中找到的所有（全局和局部）名称。

  版本3.2中的新功能。

`alias``[name [command]]`

  创建一个名为name的执行​​命令的别名。The command must not be enclosed in quotes. 可替换参数可由`%1`，`%2`等指示，而`%*`由所有参数替换。如果未给出命令，则会显示名称的当前别名。如果没有给出参数，则列出所有别名。

  别名可以嵌套，并且可以包含可以在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`

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

      (Pdb) global list_options; list_options = ['-l']
      (Pdb)

`run``[args ...]`
`restart``[args ...]`

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

`q(uit)`

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

脚注

[1] | 帧是否被认为源于某个模块由帧全局中的`__name__`确定。