Python pdb 输入 q 后,后续 breakpoint 不再停住
Python 3.15.1 的 bdb 进入帧状态可能在 BdbQuit 后未清理,影响复用调试器。确认版本和交互入口,使用新调试实例或会话规避,不修改内部标记冒充正式修复。
交互解释器里第一次调用 breakpoint() 能停住,输入 q 退出以后,再调用同一个函数却直接运行完。若错误前后解释器版本相同,先检查是否命中 Python 3.15.1 的调试器状态路径,而不是立刻重新设置所有断点。
该正式版本的 bdb 在进入跟踪分发时记录 enterframe,正常退出后清空;但清理放在 yield 后面,没有对应的 finally。q 触发 BdbQuit 等异常离开时,这个状态可能残留。后续 set_trace() 看到已有进入帧便提前返回,表现为新的断点被忽略。
先确认是复用实例后的失效
比较同一交互会话中第一次暂停与输入 q 后再次暂停的行为,同时确认 PYTHONBREAKPOINT、sys.breakpointhook 和 IDE 的调试设置没有另外禁用断点。仅某一处源码行不暂停,可能还有行号、优化或调试入口差异,不能直接归到这条路径。
该故障依赖调试器被再次使用。脚本正常因退出调试而终止,与 REPL 捕获异常后继续使用同一调试器,是不同的生命周期。不要为了观察下一次暂停,给整个业务脚本增加吞掉任意异常的处理。
使用新的调试器或新的交互会话
需要继续定位问题时,可以结束当前调试会话,在不影响业务进程的隔离复现环境里重新开始。也可在明确的调试位置新建 Pdb 实例,避免复用已经留下进入帧状态的那个对象:
import pdb
def inspect_value(value):
debugger = pdb.Pdb()
debugger.set_trace()
return value
这是交互调试示例,会暂停等待输入,不应放进无人值守生产任务。每次调用函数建立新实例,只规避这个实例的残留状态;它不会撤回之前已经运行的业务动作,也不保证修复其他 IDE 或第三方调试器的内部行为。
不要直接给库内部 enterframe 赋值来充当常规恢复方法。跟踪状态、当前帧与事件回调需要一致,随意清一个属性可能掩盖尚未退出的真正跟踪过程。
当前可核对的正式 3.15.1 仍有上述清理顺序,开放修补不能等同于已发布版本。后续采用正式修正时,保留“第一次断点、q 退出、再次断点”的完整交互复核,并确认普通继续执行和退出行为都符合预期。


