Skip to content

PyCharm 调试参考 ​

本章承接上一章的小车案例,集中整理 PyCharm 的断点、变量查看、单步执行和复核操作,作为选读参考。使用 VS Code 时,可对照这些通用步骤,在 Run and Debug 中完成相同操作。

截图说明

本章暂时沿用旧版 PyCharm 截图。截图中的工程路径、代码行号和部分按钮样式可能与当前课件不同,操作时以正文代码和自己电脑上的 PyCharm 界面为准。

断点设置与调试启动 ​

先使用上一章小车案例中的尚未修复原始程序。断点可以让程序运行到指定位置时暂停,我们先在 average_speed() 的除法语句旁边单击,设置断点:

设置断点

然后从主程序旁边的运行按钮中选择 Debug:

启动 Debug

PyCharm 会启动程序并打开调试窗口:

调试窗口

在 Console 中输入 s,重新触发刚才的问题:

控制台输入

程序执行到断点或异常位置后会暂停:

异常位置

到这里先确认两件事:

  1. 当前停在 self.odometer / self.time。
  2. Variables 区域显示 self.time 的值为 0。

断点让我们看到了程序在这一刻的真实状态。

调试状态查看 ​

程序暂停后,重点查看调用栈和变量。其他工具都围绕这两类信息展开。

调用栈 ​

调试窗口中的 Frames 会显示函数调用过程。当前案例中,可以看到程序从主流程进入 average_speed()。

调用栈和 Traceback 表达的是同一条调用关系:Traceback 是异常发生后的记录,调试窗口则允许我们在程序暂停时逐层查看。

点击不同的调用层,可以回到对应代码位置,并查看那一层可以访问的变量。

Variables 与内联值 ​

Variables 区域会列出当前作用域中的对象和变量。展开 self 后,可以看到:

  • odometer 当前为 0。
  • speed 当前为 0。
  • time 当前为 0。

PyCharm 还会把部分变量值直接显示在编辑器中:

内联调试

内联变量值适合快速浏览,Variables 更适合展开对象并检查详细状态。

监视变量(Watches) ​

如果需要持续观察某个变量,可以把它添加到 Watches:

添加监视变量

例如,在入口或 main() 的暂停位置监视 my_car.time。进入实例方法后,也可以监视 self.time,表达式要使用当前调用层能够访问的名称。程序刚启动时,它的值是 0:

监视变量初始值

重新启动后输入 a,沿正常路径继续执行,它会随着 step() 的调用发生变化:

监视变量更新后

Watches 适合回答:

  • 变量什么时候发生了变化?
  • 它是否在预期的位置变化?
  • 最终结果为什么和预期不同?

表达式求值(Evaluate Expression) ​

Evaluate Expression 可以在当前暂停位置临时计算表达式:

计算表达式

例如,可以计算:

python
self.time == 0

也可以查看:

python
self.odometer / 1

这些表达式只用于帮助判断当前状态,不会替代代码中的正式处理逻辑。避免在不了解副作用的情况下调用会修改数据的方法。

程序执行控制 ​

只看一个暂停位置还不够时,可以让程序一行一行向下执行。常用操作集中在单步调试工具栏中:

单步调试工具栏

下面的快捷键以截图所用的 PyCharm 键位为例。如果本机键位不同,可以通过按钮提示或 PyCharm 的 Keymap 设置确认。

Step Over ​

快捷键:F8

执行当前行并停到下一行。当前行调用函数时,Step Over 会完成这次调用,但不会进入函数内部。

只想查看当前函数的主流程时,优先使用 Step Over。

Step Into ​

快捷键:F7

当前行调用函数时,Step Into 会进入函数内部:

进入函数内部

怀疑问题发生在被调用函数中时,可以使用 Step Into。它也可能进入标准库或第三方库代码。

Step Into My Code ​

快捷键:Alt + Shift + F7

它同样会进入函数,但优先进入自己项目中的代码,可以减少跳入库源码的情况。

Step Out ​

快捷键:Shift + F8

已经进入函数内部,但不需要继续逐行查看时,可以使用 Step Out 运行完当前函数,回到调用它的位置。

Resume Program ​

快捷键:F9

继续运行程序,直到下一个断点、触发配置的异常暂停或程序结束:

继续执行程序

已经检查完当前位置,希望直接观察下一次暂停时,可以使用 Resume Program。

修改与复核 ​

PyCharm 可以使用 Surround With 快速包裹选中的代码,也可以直接手动编写判断:

快速包裹语句

修改 average_speed():

python
def average_speed(self):
    if self.time == 0:
        return 0
    return self.odometer / self.time

修改后重新执行原来的操作:

  1. 启动程序后立即输入 s,确认不再抛出 ZeroDivisionError。
  2. 确认平均速度显示为 0。
  3. 输入 a 让小车运行,再次输入 s。
  4. 确认 time、odometer 和平均速度会按预期变化。

如果产品规则要求“小车没有行驶时不能计算平均速度”,也可以改成输出提示。调试负责还原事实,最终怎样修改仍然要由程序需求决定。

基础调试练习 ​

第一次使用调试功能,先完成下面两个练习。

练习 1:断点检查变量 ​

使用上一章小车案例中的原始程序完成本练习;修复版会在 time == 0 时提前返回,首次输入 s 不会到达除法语句。

  1. 在 average_speed() 的除法语句设置断点。
  2. 使用 Debug 模式启动程序。
  3. 输入 s。
  4. 程序暂停后,展开 self,找到 time 和 odometer。
  5. 使用 Evaluate Expression 计算 self.time == 0。

这个练习的目标是养成习惯:不要靠猜测判断变量值,让程序停下来直接检查。

练习 2:单步检查流程 ​

先应用前面的除零修复,确保 average_speed() 能正常返回,再执行下面的步骤:

  1. 在处理 action == "S" 的位置设置断点。
  2. 使用 Debug 模式启动程序并输入 s。
  3. 使用 Step Into 进入 average_speed()。
  4. 使用 Step Out 回到调用位置。
  5. 使用 Step Over,观察什么时候执行 self.step()。

这个练习用于确认代码的真实执行顺序。

熟悉以后,在修复版程序中设置两个断点,使用 Resume Program 在两个位置之间继续运行;再分别练习 Step Over、Step Into 和 Step Out,比较它们停下来的位置。

小结 ​

本章重点掌握五件事:

  1. 排错先复现问题,写清预期结果和实际结果。
  2. Traceback 帮助定位失败位置,输出、日志和断点帮助确认运行状态。
  3. 修复方案要符合需求,程序没有报错也可能存在逻辑错误。
  4. 修改后重跑失败操作、正常操作和边界情况,用回归检查保留验证过程。
  5. AI 的原因分析和修改建议需要通过实际运行核对。