如何以编程方式退出pdb在eval()或exec()中启动而不显示输出

时间:2010-10-18 13:04:37

标签: python debugging ipython pdb

在我的python代码中,我有这一行:

try:
    result = eval(command, self.globals, self.locals)
except SyntaxError:
    exec(command, self.globals, self.locals)

command变量可以是任何字符串。因此,python调试器pdb可以在eval / exec中启动,并且在eval / exec返回时仍然处于活动状态。我想要做的是确保从eval / exec返回时恢复正常的程序执行。为了给你一个想法,这大约是我想要的行为:

try:
    result = eval(command, self.globals, self.locals)
    try: self.globals['pdb'].run('continue')
    except: pass
except SyntaxError:
    exec(command, self.globals, self.locals)
    try: self.globals['pdb'].run('continue')
    except: pass

但是try行在执行之前会显示在调试器中,但我不希望调试器显示我的代码。它也没有真正起作用......我重复代码的原因是为了最大限度地减少代码中的调试,否则我可以在except块后执行此操作。

那我该怎么做呢?

<子> 作为旁注:

如果您尝试在IPython或bpython解释器中输入以下行,您将看到他们遇到同样的问题,您可以进入他们的代码。

import pdb
pdb.set_trace()
next

但是,如果在标准cpython解释器中执行此操作,则会返回到python提示符。这样做的原因显然是因为前两个是在python中实现的,而最后一个不是。但我希望即使所有代码都是python也能获得相同的行为。

1 个答案:

答案 0 :(得分:3)

虽然我有点担心你是eval / exec'ing一个你无法控制的字符串,但我会认为你已经想到了这一点。

我认为最简单的方法是说服pdb检查每一步的堆栈帧,并在返回到所需的级别时自动恢复。你可以通过一些简单的修补来做到这一点。在下面的代码中,我将其简化为一个简单的eval,因为您真正要求的是在返回特定函数时自动恢复pdb。在您不想跟踪的函数中调用Pdb()。resume_here()。注:恢复是全球性的,只有一个恢复点,但我相信如果你愿意,你可以修改它。

如果您运行代码,那么您将在函数foo()中输入调试器,然后您可以单步执行,但只要您返回bar(),代码就会自动继续。

e.g。

import sys
from pdb import Pdb

def trace_dispatch(self, frame, event, arg):
    if frame is self._resume_frame:
        self.set_continue()
        return
    return self._original_trace_dispatch(frame, event, arg)

def resume_here(self):
    Pdb._resume_frame = sys._getframe().f_back

# hotfix Pdb
Pdb._original_trace_dispatch = Pdb.trace_dispatch
Pdb.trace_dispatch = trace_dispatch
Pdb.resume_here = resume_here
Pdb._resume_frame = None

def foo():
    import pdb
    pdb.set_trace()
    print("tracing...")
    for i in range(3):
        print(i)

def bar():
    Pdb().resume_here()
    exec("foo();print('done')")
    print("returning")

bar()