Python调试基础:调试的概念、断点调试、单步执行、查看变量
调试,说白了就是找bug的过程。你写了代码,它没按你预期跑,或者干脆报错。这时候你总不能盯着屏幕干瞪眼吧?你需要一套方法,让代码一步步告诉你,“我到底卡在哪了”。
我刚开始用Python时,调试全靠print。满屏都是print(“到这里了”)、print(a)。后来发现,这办法在小脚本里还行,一旦项目大了,print就跟蜘蛛网似的,删都删不干净。嗯,咱们今天聊的,是更专业的手段——用调试器。
调试的概念:你其实每天都在做
调试就是“观察程序执行状态,定位并修复错误”。听起来挺学术的,其实就是几个动作:
- 让程序停在某个怀疑的位置
- 检查那一瞬间所有变量的值
- 一步一步往前走,看状态怎么变的
- 找到哪里跟预期不一样,然后改代码
我曾经接手过一个项目,对接第三方API,传参总出错。肉眼看了三遍,参数名一个没拼错。后来用调试器一看,发现是某个中间函数偷偷把参数类型从int转成了str。那个错误要是靠print找,估计得印出一座喜马拉雅山。
核心思维:调试不是写代码的反面,而是写代码的一部分。你花在调试上的时间,往往是理解代码深度最好的时间。
断点调试:让程序在你想停的地方停
断点,就是你在代码行号旁边点一下,程序跑到这里会自动暂停。它不是报错,是“报到”。
我个人习惯是这样操作的:
- 在怀疑出错的那一行左侧点击,出现红色圆点
- 启动调试模式(不是直接运行)
- 程序会在红点处暂停,等待你发号施令
来看看一个简单例子。假设你有这么一段代码:
def calculate_price(base, discount):
result = base * discount
return result
total = calculate_price(100, 0.8)
print(total)
你在result = base * discount这一行设了断点。程序启动后,会停在这一行,但result还没被算出来。这时候你可以检查base和discount的值——它们应该分别是100和0.8。如果发现discount是0.08,那错误就找到了。
断点可以设多个。你可以同时怀疑三个地方,让程序依次停。调试器允许你从第一个断点继续跑到第二个断点,中间不暂停。
单步执行:像看电影一样看代码
断点只是暂停。单步执行才是真正的“慢动作回放”。常见的操作有这几种:
| 操作 | 快捷键(VS Code) | 作用 |
|---|---|---|
| 继续 | F5 | 跑到下一个断点或结束 |
| 单步跳过 | F10 | 执行当前行,不进入函数内部 |
| 单步进入 | F11 | 执行当前行,如果遇到函数就跳进去 |
| 单步跳出 | Shift+F11 | 从当前函数跳出,回到调用处 |
| 重启 | Ctrl+Shift+F5 | 从头开始调试 |
你想一想,F10和F11有什么区别?我举个例子:
def add(a, b):
return a + b
x = 10
y = 20
z = add(x, y)
print(z)
如果断点设在了z = add(x, y)这一行,按F10,调试器会直接执行add(x, y),然后停在print(z)那一行。你只知道结果,看不到add内部发生了什么。但按F11,调试器会跳到add函数的内部,让你逐行看看a和b是怎么相加的。
注意:如果你在循环里按F11,而循环里调用了函数,你会被带进函数里很多次。这时候可以先设个条件断点——右键断点,设置“当i等于100时再停”。不然你按F11按到手指抽筋。
查看变量:调试的核心目标
调试器暂停时,你真正想看的是变量。在VS Code里,左边会有一个“变量”面板,自动列出当前作用域的所有变量。你还可以把鼠标悬停在代码中的变量上,直接看到它的值。如果你在Python自带的pdb里,可以输入:
(Pdb) print(a)
(Pdb) type(a)
(Pdb) dir(a)
为什么要看变量类型?我曾经被这个问题坑过:
data = {"name": "张三", "age": "25"}
if data["age"] > 18:
print("成年")
你看出来了吗?age是个字符串“25”,不是整数25。"25" > 18在Python 3里会直接报错,因为字符串和整数不能比较。如果你用调试器一查,type(data["age"])显示<class 'str'>,问题一秒定位。
更常用的操作是在“监视”窗口添加表达式。比如你加一个len(data),调试器每次暂停都会计算这个值。这对检查大批量数据非常有用。
实战技巧:调试批量对接参数时,我习惯把每个请求的payload打印到“监视”窗口,然后用“继续”功能快速跑几十次,观察参数有没有规律性错误。比我用print一个一个看,快了不止十倍。
一个完整的调试流程 SVG
下面这张图,展示了一次典型调试的完整步骤。从怀疑bug,到定位问题,再到修复验证,每一步都清晰可见。
很多新手调试会卡在“不知道看什么”。我建议你每次停在断点,先看三样东西:
- 当前行:这是哪一步?上下文对不对?
- 局部变量:值是不是你传进来的?有没有被意外修改?
- 调用栈:程序是怎么跑到这里来的?有没有绕了远路?
看清楚了这三样,八成的问题你已经能猜个大概了。剩下两成,再单步细看。
在VS Code里,调用栈在左侧的“调用堆栈”面板。你点击栈里的任意一行,就能看到那行代码的变量。这个功能在排查“谁把我传进来的参数改了”时特别好用。
总结:调试三板斧
咱们这一章讲的,其实就是三件事:
- 断点:在哪停
- 单步:怎么走
- 变量:看什么
这三件事做好了,百分之九十的bug都可以原地消灭。下一节开始写代码练习前,我建议你先在随便一个Python脚本里按几下F11,感受一下“代码像电影一样逐帧播放”的感觉。上手之后你会发现,调试器才是你最好的代码审查工具,比任何静态检查都管用。
嗯,反正我现在写代码,调试器基本没关过。