对于一些快速的 Python 调试,我偶尔import pdb;pdb.set_trace()
会插入一行代码,让我进入调试器。非常便利。但是,如果我想调试一个循环,它可能会运行很多很多次,它会在某种程度上失去它的有效性。我可以继续混搭c
很多很多次,但是有没有办法删除/忽略那个硬编码的断点,这样我就可以让它完成?
我可以设置一个全局标志并有条件地运行它,但是我会失去单行断点的“独立性”,也需要为每个pdb.set_trace()
.
我的另一个答案是一种快速破解,并不完美(将禁用对 的所有调用set_trace
)。这是一个更好的解决方案。
我们定义了一个模块包装pdb
。其中,set_trace
是一个可调用对象,维护一个禁用调用者列表(由文件名/行号标识)。
# mypdb.py
import inspect
import sys
try:
import ipdb as PDB
except ImportError:
import pdb as PDB
class SetTraceWrapper(object):
def __init__(self):
self.callers_disabled = set()
self.cur_caller = None
def __call__(self):
self.cur_caller = self.get_caller_id()
if self.cur_caller in self.callers_disabled:
# already disabled for caller
#print 'set_trace SKIPPED for %s' % ( self.cur_caller, )
return
#print 'set_trace BREAKING for %s' % ( self.cur_caller, )
try:
PDB.set_trace(sys._getframe().f_back)
except TypeError:
PDB.set_trace()
def disable_current(self):
#print 'set_trace DISABLING %s' % ( self.cur_caller, )
self.callers_disabled.add(self.cur_caller)
def get_caller_id(self, levels_up = 1):
f = inspect.stack()[levels_up + 1]
return ( f[1], f[2] ) # filename and line number
set_trace = SetTraceWrapper()
在您的代码中,确保使用包装器:
import mypdb as pdb; pdb.set_trace()
当您想禁用当前的set_trace
呼叫线路时,请执行以下操作:
pdb.set_trace.disable_current()
笔记:
我个人更ipdb
喜欢pdb
使用时pdb
,由于实际调用的函数pdb.set_trace
在包装器中,因此中断时的当前帧将在其中。该up
命令为您提供所需的框架。ipdb
如果使用(包装器中的实现确保在正确的位置中断),则不会发生这种情况。
使用时ipdb
,我发现它报告调用者帧行号不一致。这意味着你第一次这样做pdb.set_trace.disable_current()
,它可能不成立。如果下一次它坏了,就再做一次——第二次成立。
一般来说,拥有自己的pdb
包装器对其他事情也很有用。我有自己的set_trace
包装器,可以避免中断 if not sys.stdout.isatty
(如果进程未连接到终端,也不会在将 stdout 重定向到文件/管道时中断)。也就是说,拥有自己的pdb
包装器并调用它set_trace
而不是pdb
's 是一种很好的做法。
以下 hack 将禁用当前运行中的所有其他调用set_trace
(即,从代码中的任何位置)。
创建这个noop_pdb
插件:
# noop_pdb.py
def set_trace(*args, **kwargs):
pass
然后,一旦您的代码在实际中中断pdb.set_trace
,并且您想要禁用对 的其余调用set_trace
,请执行以下操作:
sys.modules['pdb'] = __import__('noop_pdb')
下次解释器遇到如下行:
import pdb;pdb.set_trace()
它避免了重新导入内置的pdb
,拿起插件。
编辑:另一种实现这种不需要的hack的方法noop_pdb
是用noop替换set_trace
,而不是整个pdb
模块:pdb.set_trace = lambda: None
您是否尝试过使用 pdb 提供的“直到”命令?
从http://docs.python.org/2/library/pdb.html#debugger-commands:
直到)
继续执行,直到到达行号大于当前行的行或从当前帧返回。
你看了condition bpnumber
吗?您可以禁用断点,然后使其成为有条件的。或者,您可以首先使用break
或tbreak
使断点成为条件断点。详细信息可以在这里找到。
在 pdb 中使用 'return' 可以在循环中传递 pdb.set_trace() 并跳转到当前函数的最后一行。