目录
- 摘要
- 调试工具窗口
- 会话
- 工具栏
- 调试工具栏
- 单步工具栏
- 调试器选项卡
- 调用栈帧(Frames)
- 变量(Variables)
- 💡 表达式求值区域(Evaluate expression field)
- 🖱️ 右键菜单(Context Menu)
- 变量类型
- 监视(Watches)
- 表达式求值字段(Evaluate expression field)
- 工具栏(Toolbar)
- 右键菜单(Context menu)
- 调试过程
- 断点
- 断点类型
- 设置断点
- 管理断点
- 断点图标
- 启动调试器会话
- 检查挂起的程序
- 逐步执行程序
- 使用 PyCharm 进行远程调试
- 使用调试控制台
- 尾声
摘要
写代码这么多年,我一直是“打印派”的忠实拥趸。每当程序出了问题,我下意识地就在关键位置加上 print()
或 pprint()
来输出变量、状态或者程序流程。对于一些小项目,这种方式确实简单高效,也容易快速定位问题。
但当我开始开发更加复杂的应用,比如 AI Agent 系统,print 调试就显得力不从心了。大量的模块调用、异步逻辑、状态切换,让单纯靠打印信息已经难以理清整个程序的运行脉络。而一不小心,满屏的调试信息不仅没帮我找到问题,反而制造了更多干扰。
这时候,我开始认真学习 PyCharm 的调试工具。从最基本的断点设置,到条件断点、变量追踪、堆栈查看,再到 Evaluate Expression、数据修改和多线程调试等进阶功能,PyCharm 提供了一整套强大的调试能力,几乎能覆盖所有开发场景。
本篇博客将系统讲解我从“print 调试”逐步转向“IDE 调试”的心路历程,并结合一些真实的项目案例,介绍如何使用 PyCharm 的 Debug 功能来高效排查和解决复杂问题。无论你是初学者,还是像我一样长年“只用打印”的开发者,都可以从中找到属于你的调试利器。
调试工具窗口
当你启动调试会话时,Debug 工具窗口会自动打开。你可以使用这个窗口来控制调试过程,查看和分析程序数据(如调用栈、变量等),并执行各种调试操作。
默认情况下,当程序运行到断点时,Debug 工具窗口会自动打开,并且在调试会话结束后不会自动关闭。
如果你想修改这个行为,可以前往 Build, Execution, Deployment | Debugger 设置页面(快捷键 Ctrl+Alt+S
),取消勾选 Show debug window on breakpoint(在断点处显示调试窗口) 选项即可。
-
- Sessions tabs:会话选项卡
-
- Debugger console tab:调试器控制台选项卡
-
- Variables and watches:变量与监视
-
- Frames:调用栈帧
-
- Debugger toolbar:调试工具栏
会话
可用的调试会话被分隔在 调试 工具窗口顶部的选项卡中。
如果您为特定的运行/调试配置 启用了服务工具窗口 ,那么当您调试这些配置时,调试工具窗口的整个视图将显示在服务工具窗口中。
编辑器中的所有信息,例如 内联变量值和执行点,都会显示在选定的会话选项卡中。 如果您同时运行多个使用相同的调试会话,这一点很重要。
当您关闭一个选项卡时,相应的调试会话会终止。
工具栏
调试器工具栏包含 控制调试器会话和 单步操作的最常用操作。
您可以根据自己的喜好配置工具栏上可用的操作列表。
-
要添加调试操作,请右键单击调试器工具栏,从上下文菜单中选择 添加到调试器工具栏 ,然后从列表中选择所需的操作。
-
要添加与调试无直接关系的操作,请右键单击调试器工具栏,然后从上下文菜单中选择 自定义工具栏。
在打开的对话框中,单击 添加 ,然后选择所需的操作。
调试工具栏
无论选择了哪个选项卡,您始终可以在窗口左侧使用以下工具栏控件,以传统UI为例:
项目 | 工具提示和快捷键 | 描述 |
---|---|---|
重新运行 CtrlF5 | 点击此按钮以停止当前应用程序并再次运行(继续运行直到下一个断点)。 | |
恢复程序 F9 | 当应用程序暂停时,点击此按钮以恢复程序执行。 | |
暂停程序 Ctrl+Pause | 点击此按钮以暂停程序执行。 | |
停止 CtrlF2 | 单击此按钮通过标准 | |
查看断点 CtrlShiftF8 | 点击此按钮以打开 断点 对话框,您可以在其中配置断点行为。 | |
静音断点 | 使用此按钮切换断点状态。 当 您可以暂时静音项目中的所有断点,以便在不中断断点的情况下执行程序。 | |
设置 | 点击此按钮以打开包含以下选项的菜单:
| |
固定选项卡页 | 点击此按钮以固定或取消固定当前选项卡。 当窗口中的标签页达到最大数量时,您可能需要将一个标签页固定,防止其自动关闭。 |
单步工具栏
项目 | 工具提示和快捷键 | 描述 |
---|---|---|
显示执行点 AltF10 | 点击此按钮以突出显示编辑器中的当前执行点,并在 窗口 窗格中显示相应的堆栈帧。 | |
步过 F8 | 点击此按钮以执行程序,直到当前方法或文件中的下一行,跳过当前执行点引用的方法(如果有)。 如果当前行是方法中的最后一行,执行步骤将跳转到该方法之后执行的行。 | |
步入 F7 | 点击此按钮以使调试器进入当前执行点调用的方法。 | |
强制步入 AltShiftF7 | 点击此按钮以使调试器进入当前执行点中调用的方法,即使该方法将被跳过。 | |
单步执行我的代码 AltShiftF7 | 点击此按钮以跳过进入库源代码,并专注于您的代码。 | |
步出 ShiftF8 | 点击此按钮可使调试器退出当前方法,并跳至其后执行的行。 | |
运行到光标处 AltF9 | 点击此按钮以恢复程序执行,并暂停直到执行点到达编辑器中当前光标位置的行。 不需要断点。 实际上,在光标处为当前行设置了一个临时断点,一旦程序执行暂停,该断点就会被移除。 因此,如果文本光标位于已执行的行,程序将只是恢复执行,因为无法回滚到先前的断点。 此操作在您深入方法序列且需要一次退出多个方法时特别有用。 如果在应该执行的行上设置了断点,在到达指定行之前,调试器会在遇到的第一个断点处暂停。 tip:当您需要在特定行设置一种临时断点,而程序执行不应中断时,请使用此操作。 | |
评估表达式 AltF8 | 点击此按钮可 评估表达式。 |
调试器选项卡
调用栈帧(Frames)
Threads & Variables 选项卡中的 Frames 面板(调用栈帧)可用于查看当前应用程序中的所有线程列表。
要检查某个线程,只需从面板顶部的线程列表中选择它。每个线程的状态和类型会通过图标和线程名称旁的文字说明进行标识。
对于选中的线程,你可以:
- 查看其调用栈帧(Stack Frame)
- 展开并检查各级帧(函数调用)
- 在帧之间导航
- 自动跳转到该帧对应的源代码位置
如需查看某个调用帧中保存的变量值,请使用 Debug 工具窗口中的 Variables(变量) 面板。
线程图标(每个线程旁的图标表示该线程的状态):
变量(Variables)
Threads & Variables 选项卡中的 Variables 面板 可用于查看应用程序中各个对象的实际值。
当你在 Frames 面板 中选中了某个调用栈帧后,Variables 面板 会显示该帧作用域内的所有数据,包括方法参数、本地变量和实例变量等。
在这个面板中,你可以执行以下操作:
- 为对象设置标签
- 展开并查看对象的内部结构
- 评估任意表达式
- 将变量添加到监视列表(Watches)
- 以及更多调试相关操作
💡 表达式求值区域(Evaluate expression field)
当 Watches 面板 处于隐藏状态时,Variables 面板 中会显示一个 “表达式求值” 输入框,用于直接输入并计算任意表达式。
- 要评估某个表达式,只需在此字段中输入表达式,然后按
Enter
键即可。 - 结果将直接显示在下方。你还可以点击输入框右侧的图标,将该表达式添加到监视列表中,便于后续持续追踪。
🖱️ 右键菜单(Context Menu)
项目 | 快捷键 | 说明 |
---|---|---|
新建监视(New Watch) | – | 创建一个新的监视表达式。会打开一个文本输入框,你可以在其中输入要监视的表达式。 |
删除监视(Remove Watch) | Delete | 删除当前选中的监视表达式。 |
编辑(Edit) | F2 | 修改当前选中的监视表达式。 |
删除所有监视(Remove All Watches) | – | 一次性删除所有监视表达式。 |
自定义数据视图(Customize Data View) | – | 添加自定义类型渲染器(type renderer),用于以特定方式展示某些对象。 |
检查(Inspect) | – | 适用于字段、局部变量和引用表达式。打开一个非模态的“检查”窗口,便于集中查看某个对象引用。你可以同时打开多个检查窗口,它们的视图与监视面板一致,但更节省空间。 |
设置值(Set Value) | F2 | 修改某个字段或变量在运行时的值。 |
复制值(Copy Value) | Ctrl+C | 将选中变量的值复制到剪贴板。如果选中多个变量,不仅值会被复制,结构也会保留,粘贴到文本文件时格式会自动缩进,类似调试器的树形结构,方便阅读。你也可以将鼠标悬停在值上查看其内容。 |
复制 JSON(Copy JSON) | – | 仅在 JavaScript 上下文中可用。以 JSON 格式复制选中的值。 |
与剪贴板中的值比较(Compare Value with Clipboard) | – | 将当前选中变量的值与剪贴板中的内容进行比较。 |
复制名称(Copy Name) | – | 复制当前选中变量的名称到剪贴板。 |
评估表达式(Evaluate Expression) | Alt+F8 | 在弹出的对话框中对选中的变量进行表达式求值。 |
添加到监视(Add to Watches) | – | 为当前选中的节点(非静态节点)创建表达式并添加到监视面板中。 |
显示引用此对象的实例(Show Referring Objects) | – | 查看哪些对象引用了当前选中的变量。 |
跳转到源代码(Jump to Source) | F4 | 在编辑器中打开该变量或字段所在的源代码,并将光标定位到对应行。 |
跳转到类型定义(Jump to Type Source) | F4 | 跳转到当前变量或字段所属类的定义位置。 |
查看为(View as) | – | 选择变量值的显示格式。 🔹 Hex(十六进制):适用于数值变量。 🔹 Binary(二进制):适用于二进制数据。 |
查看为数组(View as Array) | – | 适用于表示 NumPy 数组的变量。需要在解释器中安装 NumPy。也可以点击变量旁边的 View as Array 链接。 |
查看为图像(View as Image) | – | 适用于 NumPy 的 1D/2D/3D 数组变量。需要安装 NumPy 和 Pillow。 |
查看为 DataFrame(View as DataFrame) | – | 适用于表示 pandas DataFrame 的变量。需要在解释器中安装 pandas。也可以点击变量旁边的 View as DataFrame 链接。 |
变量类型
每个变量左侧的图标表示其类型:
:数组
:原始类型
:对象
监视(Watches)
在 Watches 面板 中,你可以在当前调用栈帧的上下文中评估任意数量的变量或表达式。每当程序执行到下一步时,这些表达式的值都会自动更新,并在程序暂停时显示出来。
虽然你可以通过 Variables 面板 的右键菜单使用 “Evaluate Expression(评估表达式)” 来查看某一个表达式的值,但 Watches 面板 可以同时显示多个表达式,并且在多个调试会话之间保持不变,直到你主动删除它们。
你可以通过以下方式添加监视表达式:
- 在 Watches 面板 中直接添加
- 在 Variables 面板 中右键添加
- 在编辑器中选中表达式并添加
所有监视表达式都会在当前选中的调用栈帧(Frames 面板)的上下文中进行评估。
如果某个表达式无法被评估,其值会显示为问号 ?
。
默认情况下,Watches 面板是隐藏的,此时监视表达式会直接显示在 Variables 面板 中。
如果你希望 Watches 面板单独显示:
- 点击调试工具栏中的 Layout Settings(布局设置) 按钮
- 选择 Separate Watches(分离显示监视面板)
这样就能将监视表达式独立显示,便于统一查看和管理。
表达式求值字段(Evaluate expression field)
要评估任意表达式,只需在 Watches 面板 中的 表达式求值字段 输入表达式并按下 Enter
键。
结果会立即显示在下方。你还可以点击输入框右侧的图标,将该表达式添加到监视列表中。
工具栏(Toolbar)
项目 | 快捷键 | 描述 |
---|---|---|
插入 | 点击此按钮以创建新监视。 | |
Delete | 点击此按钮以从列表中移除选定的监视。 | |
| Alt0↑ Alt0↓ | 使用这些按钮更改监视的顺序。 |
Ctrl0D | 使用此按钮创建选定监视的副本。 | |
在变量选项卡中显示监视 | 使用此切换按钮隐藏或显示 监视 窗格。 默认情况下,该按钮被按下并显示在 变量 窗格的工具栏上。 因此, 监视 窗格被隐藏,监视显示在 变量窗格 中。
|
右键菜单(Context menu)
项目 | 快捷键 | 描述 |
---|---|---|
新建监视(New Watch) | — | 选择此命令以创建一个新的监视表达式。将打开一个文本字段用于输入新的表达式。 |
删除监视(Remove Watch) | Delete | 删除当前选中的监视表达式。 |
编辑(Edit) | F2 | 修改当前选中的监视表达式。 |
删除所有监视(Remove All Watches) | — | 删除列表中的所有监视表达式。 |
检查(Inspect) | — | 可用于字段、局部变量和引用表达式,打开一个非模态的检查窗口,用于专注查看特定引用。你可以打开任意数量的检查窗口。窗口视图与 Watches 面板一致,但占用空间更少。 |
显示引用对象(Show Referring Object) | — | 显示引用当前监视表达式的所有对象列表。 |
复制值(Copy Value) | Ctrl + C | 复制选中变量的值到剪贴板。如果选中多个项,不仅会复制变量值,还会复制其结构(类似调试器的树形结构),粘贴到文本文件时有良好缩进格式。 也可以将鼠标悬停在值上,在工具提示中查看内容。 |
复制 JSON(Copy JSON) | — | 仅适用于 JavaScript 环境,将选中的值以 JSON 格式复制。 |
与剪贴板比较值(Compare Value with Clipboard) | — | 将当前值与剪贴板中的值进行比较。 |
复制名称(Copy Name) | — | 将选中变量的名称复制到剪贴板。 |
计算表达式(Evaluate Expression) | Alt + F8 | 在弹出的对话框中计算所选变量的表达式。 |
添加到监视(Add to Watches) | — | 可用于除静态节点外的所有节点。创建一个引用该节点的表达式并添加到 Watches 面板中。 |
显示引用对象(Show Referring Objects) | — | 显示当前选中变量被哪些对象引用。 |
跳转到源代码(Jump to Source) | F4 | 在编辑器中打开该变量或字段的源代码,并将光标定位到对应的行。 |
跳转到类型定义(Jump to Type Source) | F4 | 跳转到所选变量或字段所属类的定义处。 |
以其他格式查看(View as) | — | 设置变量值的显示方式。对于整数类型,可选择二进制、十进制或十六进制: - Hex:十六进制显示 - Binary:二进制字面量显示 |
以数组查看(View as Array) | — | 适用于 NumPy 数组类型的变量。需确保 Python 解释器中已安装 NumPy。也可以点击变量旁的 “View as Array” 链接。 |
以图像查看(View as Image) | — | 适用于 1D/2D/3D 的 NumPy 数组变量。需确保已安装 NumPy 和 Pillow。 |
以数据表查看(View as DataFrame) | — | 适用于 pandas 数据框类型变量。需确保已安装 pandas。也可以点击变量旁的 “View as DataFrame” 链接。 |
调试过程
断点
断点是特殊的标记,用于在程序执行到特定位置时暂停运行。这样你就可以检查程序的状态和行为。断点可以很简单,比如程序执行到某一行代码时暂停;也可以更复杂,比如根据额外条件判断是否暂停、写入日志等操作。
设置断点后,它会一直保留在你的项目中,除非你主动删除它,临时断点除外。
如果包含断点的文件被外部修改(例如通过版本控制系统更新或在外部编辑器中更改),且行号发生了变化,断点会相应地自动调整位置。请注意,此类更改发生时,PyCharm 必须处于运行状态,否则这些更改将不会被检测到。
断点类型
PyCharm 支持以下几种断点类型:
-
行断点:程序执行到设置断点的代码行时暂停。此类型断点可以设置在任何可执行的代码行上。
-
异常断点:当抛出 Exception 或其子类时暂停程序。在 PyCharm 中,你可以为 Python 异常设置断点。对于 PyCharm Professional 版,还支持 Django、Jinja2、JavaScript 和 Jupyter 的异常断点。这些断点对异常条件全局生效,不需要特定的源码位置。与仅查看堆栈跟踪不同,异常断点暂停程序时,可以让你在异常上下文或数据仍然可用时进行检查。
设置断点
-
设置行断点:
点击可执行代码行的装订区域,设置断点。 或者,将文本光标放在行上并按下 CtrlF8。
-
设置异常断点
管理断点
-
移除断点
-
静音断点:如果您暂时不需要在断点处暂停,可以将其 静音。 这使您能够在不离开调试器会话的情况下恢复正常程序操作。 之后,您可以取消静音断点并继续调试。
点击 静音断点 按钮
在 调试 工具窗口的工具栏中。
-
启用/禁用断点,当您移除断点时,其 内部配置会丢失。 若要在不丢失断点参数的情况下暂时关闭单个断点,您可以 disable 它:
对于非异常断点:右键点击并根据需要设置 已启用 选项。 您还可以用中键切换它们,如果移除断点没有 assigned 到它。
对所有断点:点击 运行 | 查看断点 CtrlShiftF8 ,然后在列表中选中/取消选中断点。
断点图标
根据它们的 类型和 状态 ,中断点会被标记以下图标:
行 | 异常 | |||
---|---|---|---|---|
常规 | ||||
已禁用 | ||||
已验证 | ||||
静音 | ||||
非活动/依赖 | ||||
静音已禁用 | ||||
非挂起 | ||||
已验证的非挂起 | ||||
无效 |
启动调试器会话
启动调试器会话与以正常模式运行程序非常相似。 调试器在后台附加,因此您无需配置任何特定内容即可开始调试会话。 如果您能够从 PyCharm 运行您的程序,您也可以使用相同的配置对其进行调试。
检查挂起的程序
在调试器会话 启动后, Debug工具窗口会出现,程序会正常运行,直到发生以下情况之一:
-
触发了一个 breakpoint
-
手动 暂停程序
之后,程序将被挂起,允许用户检查其当前状态、控制其进一步执行并在运行时测试各种场景。
程序的状态由 frames表示。 当程序暂停时,当前的帧堆栈将显示在 帧 选项卡中的 调试 工具窗口内。
帧对应于活动的方法或函数调用。 它存储了被调用方法或函数的局部变量、其参数以及使表达式求值成为可能的代码上下文。
每次调用 方法 时,都会在栈顶新增一个帧。 当 方法 的执行完成时,相应的帧将从堆栈中移除(最后一个进,最先一个出)。
检查帧有助于您了解为什么特定参数被传递给方法,以及调用者在调用时的状态。
变量 选项卡显示所选 帧/线程中的变量列表。 检查变量可以帮助您理解程序为何以某种方式运行。
如果您想测试程序在特定数据下的行为或在运行时更改其流程,可以通过更改变量值来实现。
PyCharm 允许您在调试会话中评估表达式,以获取有关程序状态的更多详细信息或在运行时测试各种执行场景。
此功能仅在程序在命中断点后暂停(而非 暂停 )时有效。
指向您要计算的表达式。 表达式的结果显示在工具提示中。
逐步执行程序
PyCharm 提供了一组单步操作,具体使用取决于您的策略,例如您是需要直接跳到下一行还是检查中间的方法调用。
使用 PyCharm 进行远程调试
使用 PyCharm,你可以通过位于另一台计算机上的解释器调试你的应用程序,例如,位于 Web 服务器或专用测试机上。
PyCharm 提供两种远程调试方式:
-
通过远程解释器
- 适用场景:利用远程机器上更强大的调试功能。
- 要求:本地机器需通过 SSH 访问远程服务器。
-
使用 Python 远程调试服务器配置
- 适用场景:将调试过程集成到远程服务器上的多个运行进程中。当你无法显式启动应用程序进行调试,或者需要进行某些准备工作时,这种方式非常有用。
- 要求:本地机器需通过 SSH 访问远程服务器,且远程服务器需能通过任意预定义端口访问本地机器。
在此示例中,运行您的应用程序的机器被称为 local ,而具有远程解释器的机器被称为 remote。
配置远程解释器:
将您的应用程序部署到远程主机:
查看调试输出。 请注意,调试实际上是在指定的远程服务器上进行的。
使用调试控制台
调试控制台使您能够查看输出和错误消息。
默认情况下,控制台是交互式的。 它将显示提示,您可以使用代码补全执行命令。
您可以通过点击 显示调试控制台 来禁用此行为。
在控制台中,您可以:
尾声
写到这里,其实我们已经把 PyCharm 的调试功能基本过了一遍。无论是最基础的断点设置、变量观察,还是更高级的表达式求值、远程调试、查看引用对象等功能,PyCharm 都提供了非常直观且强大的工具来支持日常开发中的调试工作。
可能一开始你会觉得这些窗口和按钮有点多、有点乱,但只要你真正开始用起来,比如在调不通的代码上打个断点、一步步查看变量值,慢慢你就会意识到这些工具有多香。不用满屏 print()
,不用瞎猜代码在哪出错,整个调试过程就像在看一部代码的“慢动作电影”,每一帧都能掌控。
更别说远程调试这个能力了,对于需要部署到服务器、或者跑在 Docker、虚拟机里的项目来说,它简直就是救命稻草。配置好一次之后,你就可以像本地调试一样去控制远程代码的执行,非常方便。
总之,如果你平时写 Python 项目,尤其是中大型项目,强烈建议把 PyCharm 的调试工具真正用起来。会调试,远比只会写代码更重要,它能帮你节省大量排查 bug 的时间,也能让你对程序的执行流程有更深的理解。希望这篇文章能帮你更快上手,也欢迎你继续去探索更多好用的小技巧!