VSCode调试依赖debugpy而非pdb,因pdb不支持DAP协议;正确配置需设"type": "debugpy"、"justMyCode": true、"console": "integratedTerminal"。

VSCode 默认用的是 debugpy,不是 Python 内置的 pdb;所谓“内置调试器”在 VSCode 语境下是误称,真正起作用的是 debugpy 这个独立进程式调试服务器。
为什么不能直接用 pdb 启动调试会话
VSCode 的调试协议(DAP)要求调试器以语言服务形式运行,pdb 是交互式命令行工具,不支持 DAP。你手动执行 python -m pdb script.py 可以用,但无法和 VSCode 的变量面板、断点管理、调用栈联动——它压根不在同一个通信通道里。
常见错误现象:
- 在 launch.json 中把
"type"写成"pdb"→ 启动失败,报错Unknown debugger type 'pdb' - 在代码里写
import pdb; pdb.set_trace()→ 程序停住,但 VSCode 调试界面无响应,变量面板空白,F10/F11 失效
正确做法是:让 debugpy 接管所有断点逻辑,而不是把 pdb 当作替代品混用。
立即学习“Python免费学习笔记(深入)”;
launch.json 中必须设对的三个关键字段
很多调试异常(比如变量不显示、跳进标准库、justMyCode 失效)都源于这几个配置没对齐:
-
"type": "debugpy"—— 必须显式写,不能省略或写错大小写 -
"justMyCode": true—— 关键开关,设为false会导致调试器钻进site-packages甚至 Python 标准库,大幅拖慢单步速度 -
"console": "integratedTerminal"或"internalConsole"—— 前者能捕获input()和子进程输出,后者在旧版 VSCode 中可能丢掉某些 stdout 流;若用matplotlib或需 GUI 交互,建议选integratedTerminal
示例最小可靠配置:
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": true
}
]
}
Watch 面板里写表达式要注意作用域和求值时机
Watch 面板不是 Python REPL,它只在断点暂停时做一次求值,且受限于当前栈帧的作用域。
容易踩的坑:
- 写
len(my_list)没问题,但写my_list.append(1)→ 不报错但无效果,因为这是语句,不是表达式 - 在函数 A 里加 Watch
global_var,但断点设在函数 B 内部 → 显示ReferenceError,因为此时global_var不在当前作用域链中 - 监视嵌套对象如
data['items'][0].name→ 若中间某层为None,整个表达式直接报TypeError,不会优雅 fallback
建议:Watch 只用于读取和简单计算;复杂逻辑改用调试控制台(Debug Console),那里支持多行、赋值、导入模块。
条件断点和日志点的实际约束
条件断点看似强大,但 debugpy 对 Python 表达式的支持有边界:
- 条件中不能含函数调用(如
is_valid(x))、f-string、lambda、或任何需要编译为字节码的结构 - 只接受纯表达式:比较运算、布尔逻辑、属性访问、索引、字面量 —— 本质是
eval()安全子集 - 日志点(Logpoint)里的模板字符串如
value={x}, count={i},大括号内也受同样限制;不能写{x.upper()}
性能影响:每个断点命中时都要解析并执行条件表达式。在高频循环里设条件断点(如 i == 999)比设普通断点 + 手动 F10 跳过更慢,因为每次迭代都 eval 一次。
真正难搞的从来不是怎么设断点,而是搞清当前停在哪一帧、变量从哪来、为什么 watch 里看不到你刚改的值——这些细节藏在调用栈折叠状态、justMyCode 开关、以及 debugpy 实际 attach 的进程上下文里。


















