3

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

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

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

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 也能获得相同的行为。

4

1 回答 1

3

虽然我有点担心您正在评估/执行一个您无法控制的字符串,但我假设您已经考虑过了。

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

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

例如

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()
于 2010-12-06T11:36:27.090 回答