Python 调试工具

在所有编程练习中,如果没有方便的调试器,很难深入。Python 内置的调试器 `pdb` 已经成熟且功能强大,如果您知道如何使用它,它将为您提供很大帮助。在本教程中,我们将了解 `pdb` 能为您做些什么以及它的一些替代品。

在本教程中,您将学习

  • 调试器能做什么
  • 如何控制调试器
  • Python 的 pdb 的局限性及其替代品

用我的新书 Python for Machine Learning 启动您的项目,包括分步教程和所有示例的 Python 源代码文件。

让我们开始吧。

Python 调试工具
摄影:Thomas Park。保留部分权利。

教程概述

本教程分为 4 个部分;它们是

  • 运行调试器的概念
  • 使用调试器的演练
  • Visual Studio Code 中的调试器
  • 在运行中的 Python 程序上使用 GDB

运行调试器的概念

调试器的目的是为您提供一个慢动作按钮,以控制程序的流程。它还允许您在特定时间冻结程序并检查其状态。

调试器下最简单的操作是单步执行代码。即一次运行一行代码,并等待您的确认后再进行下一行。我们希望以停止和启动的方式运行程序的原因是,这使我们能够检查逻辑和值,或验证算法。

对于较大的程序,我们可能不想从头开始单步执行代码,因为可能需要很长时间才能到达我们感兴趣的行。因此,调试器还提供了一个断点功能,当到达特定代码行时会启动。从那时起,我们可以逐行单步执行。

使用调试器的演练

让我们通过一个例子来看看如何使用调试器。下面是用于动画显示 粒子群优化 的 Python 代码

粒子群优化通过多次执行 update() 函数来完成。每次运行时,我们都更接近目标函数的最佳解。我们使用 matplotlib 的 FuncAnimation() 函数而不是循环来运行 update(),这样我们就可以捕获每次迭代中粒子的位置。

假设此程序保存为 pso.py。要在命令行中运行此程序,只需输入

解决方案将打印到屏幕上,动画将保存为 PSO.gif。但如果我们要使用 Python 调试器运行它,我们在命令行中输入以下内容

-m pdb 部分将加载 pdb 模块并让该模块为您执行文件 pso.py。当您运行此命令时,您将看到如下所示的 pdb 提示符

在提示符下,您可以输入调试器命令。要显示支持的命令列表,我们可以使用 h。要显示特定命令(例如 list)的详细信息,我们可以使用 h list

在调试会话开始时,我们从程序的第一行开始。通常,Python 程序会以几行 import 开始。我们可以使用 n 移动到下一行,或者使用 s 进入一个函数

pdb 中,代码行会在提示符之前打印。通常,我们更喜欢 n 命令,因为它执行该行代码并将流程移动到相同级别,而不会深入。当我们在调用函数的行(例如上述程序的第 11 行,运行 z = f(x, y))时,我们可以使用 s 进入该函数。

在上面的示例中,我们首先进入 f() 函数,然后再次单步执行计算,最后从函数中收集返回值并将其返回给调用该函数的行。我们看到,即使是像单行函数这样简单的函数,也需要多个 s 命令,因为从语句中找到函数、调用函数和返回函数都需要一个步骤。我们还可以看到,在函数体中,我们像调用函数一样调用了 np.sin(),但调试器的 s 命令没有进入其中。这是因为 np.sin() 函数不是用 Python 实现的,而是用 C 实现的。pdb 不支持编译后的代码。

如果程序很长,多次使用 n 命令移动到我们感兴趣的位置会非常无聊。我们可以使用带有行号的 until 命令让调试器运行程序直到到达该行

until 类似的命令是 return,它将执行当前函数直到即将返回的点。您可以将其视为 until,其行号等于当前函数的最后一行。until 命令是一次性的,这意味着它只会将您带到该行。如果您想在特定行每次运行时都停止,我们可以在其上设置断点。例如,如果我们对优化算法的每次迭代如何移动解决方案感兴趣,我们可以在应用更新后立即设置一个断点

设置断点后,我们可以在满足触发条件之前让调试器运行程序。c 命令表示继续直到满足触发条件。在任何时候,我们都可以使用 bt 命令显示回溯以检查我们是如何到达该点的。我们还可以使用 p 命令打印变量(或表达式)以检查它们所持有的值。

实际上,我们可以设置带有条件的断点,这样它只有在满足条件时才会停止。以下将设置一个条件,即第一个随机数(r1)大于 0.5

实际上,我们也可以在调试时尝试操作变量。

在上面,我们使用 l 命令列出当前语句(由箭头 -> 标识)周围的代码。在列表中,我们还可以看到断点(用 B 标记)设置在第 40 行。由于我们可以看到 Vr1 的当前值,我们可以将 r1 从 0.54 修改为 0.2,并使用 j(跳转)命令再次运行第 38 行的语句。我们看到,在使用 n 命令执行语句后,V 的值发生了变化。

如果我们使用断点并发现意外情况,则很可能是由调用堆栈中不同级别的问题引起的。调试器允许您导航到不同的级别

在上面,第一个 bt 命令给出了我们在最底层帧(即调用堆栈的最深处)时的调用堆栈。我们可以看到我们即将执行语句 X = X + V。然后 up 命令将我们的焦点向上移动一层调用堆栈,即运行 update() 函数的行(如我们看到的以 > 开头的行)。由于我们的焦点发生了变化,列表命令 l 将打印不同的代码片段,p 命令可以检查不同作用域中的变量。

以上涵盖了调试器中大多数有用的命令。如果我们想终止调试器(这也终止程序),我们可以使用 q 命令退出,如果您的终端支持,也可以按 Ctrl-D。

想要开始学习 Python 机器学习吗?

立即参加我为期7天的免费电子邮件速成课程(附示例代码)。

点击注册,同时获得该课程的免费PDF电子书版本。

Visual Studio Code 中的调试器

对 Python 编码更有信心

如果您不太习惯在命令行中运行调试器,您可以依靠 IDE 中的调试器。几乎所有 IDE 都会为您提供一些调试功能。例如,在 Visual Studio Code 中,您可以在“运行”菜单中启动调试器。

在运行中的 Python 程序上使用 GDB

Python 的 pdb 只适用于从头开始运行的程序。如果一个程序已经在运行但卡住了,我们无法使用 pdb 挂钩进去检查发生了什么。然而,GDB 的 Python 扩展可以做到这一点。

为了演示,我们考虑一个 GUI 应用程序。它会一直等待用户的操作,程序才能结束。因此,这是一个完美的示例,说明我们如何使用 gdb 挂钩到正在运行的进程中。下面的代码是一个使用 PyQt5 的“hello world”程序,它只是创建一个空窗口并等待用户关闭它

我们将此程序保存为 simpleqt.py,并在 Linux 的 X 窗口环境中运行它,使用以下命令

末尾的 & 将使其在后台运行。现在我们可以使用 ps 命令检查其进程 ID

ps 命令将在第一列中告诉您进程 ID。如果您的 gdb 安装了 Python 扩展,我们可以运行

它将带您进入 GDB 的提示符

GDB 应该是一个用于编译程序(通常是 C 或 C++)的调试器。Python 扩展允许您检查正在由 Python 解释器(用 C 编写)运行的代码(用 Python 编写)。在处理 Python 代码方面,它的功能不如 Python 的 PDB 丰富,但当您需要将其挂钩到正在运行的进程中时,它非常有用。

GDB 支持的命令有 py-listpy-btpy-uppy-downpy-print。它们与 pdb 中没有 py- 前缀的相同命令相当。

如果您的 Python 代码使用从 C 编译的库(例如 numpy),并且您想调查其运行方式,GDB 会很有用。检查运行时调用堆栈以了解程序冻结的原因也很有帮助。但是,您可能很少需要使用 GDB 来调试您的机器学习项目。

进一步阅读

Python pdb 模块的文档位于

pdb 并不是唯一可用的调试器。一些第三方工具列在

对于带有 Python 扩展的 GDB,最好在 Linux 环境中使用。有关其用法的更多详细信息,请参阅以下内容

pdb 的命令接口受 GDB 影响。因此,我们可以从后者中学习一般调试程序的技术。一本关于如何使用调试器的优秀入门书是

总结

在本教程中,您了解了 Python 的 pdb 的功能。

具体来说,你学到了:

  • pdb 能做什么以及如何使用它
  • pdb 的局限性和替代品

在下一篇文章中,我们将看到 pdb 也是一个可以在 Python 程序中调用的 Python 函数。

掌握 Python 机器学习!

Python For Machine Learning

更自信地用 Python 编码

...从学习实用的 Python 技巧开始

在我的新电子书中探索如何实现
用于机器学习的 Python

它提供了带有数百行可运行代码自学教程,为您提供包括以下技能
调试性能分析鸭子类型装饰器部署等等...

为您高层级展示 Python 工具箱,用于
您的项目


查看内容

Python 调试工具的 9 条回复

  1. Sean McCarthy 2022 年 1 月 14 日 上午 7:44 #

    对 GDB 的解释很好。我用过 PDB,但从没用过 GDB。谢谢!

    • James Carmichael 2022 年 1 月 14 日 上午 8:48 #

      感谢您的反馈和好评,肖恩!

  2. sdfsfd 2022 年 1 月 14 日 晚上 10:00 #

    sdfsdf

  3. Dale 2022 年 1 月 15 日 上午 12:41 #

    看看 ipdb,它提供了类似于 ipython 的接口。

    • James Carmichael 2022 年 1 月 15 日 上午 11:26 #

      感谢您的建议,Dale!

  4. nav 2022 年 1 月 16 日 晚上 10:26 #

    非常棒的文章。关于 gdb 用法的信息是宝藏。

    • James Carmichael 2022 年 1 月 17 日 上午 7:09 #

      感谢您的反馈和好评,Nav!

      • Ivo Almeida 2022 年 4 月 11 日 上午 5:53 #

        感谢您如此精彩的解释。我以前不知道 DGB。

        • James Carmichael 2022 年 4 月 14 日 上午 3:42 #

          感谢您的反馈,Ivo!

发表回复

Machine Learning Mastery 是 Guiding Tech Media 的一部分,Guiding Tech Media 是一家领先的数字媒体出版商,专注于帮助人们了解技术。访问我们的公司网站以了解更多关于我们的使命和团队的信息。