Python pdb(调试器)中 disp 的等效命令是什么?

10 投票
3 回答
1618 浏览
提问于 2025-04-17 08:26

在gdb中,有没有和disp功能相似的pdb命令呢?

比如,当我用gdb调试C语言时,我可以通过输入以下命令,让变量在每一步执行时自动打印出来:

disp var

但是当我用pdb调试Python时,我希望也能有类似的功能,但似乎没有disp这个命令,Python的pdb文档里也没有提供替代的选项,这是不是有点奇怪呢?

3 个回答

1

在使用pdb调试的时候,你可以输入普通的Python代码,不仅仅是那些单字母的命令。所以你可以直接使用 print var 这样的代码来查看变量的值。

3

你可以设置一些别名,这样就能帮你完成这个任务:

alias n next;; p var
alias s step;; p var

打印出一整列变量名的工作就留给你自己去做了。不幸的是,这种方式意味着当你给调试器发送一个空行时,它执行的“最后一个命令”是 p var,而不是比如说 n。如果你想解决这个问题,可以使用这组稍微有点技巧的 Pdb 命令:

!global __stack; from inspect import stack as __stack
!global __Pdb; from pdb import Pdb as __Pdb
!global __pdb; __pdb = [__framerec[0].f_locals.get("pdb") or __framerec[0].f_locals.get("self") for __framerec in __stack() if (__framerec[0].f_locals.get("pdb") or __framerec[0].f_locals.get("self")).__class__ == __Pdb][-1]

alias s step;; p var;; !__pdb.lastcmd = "!__pdb.cmdqueue.append('s')"
alias n next;; p var;; !__pdb.lastcmd = "!__pdb.cmdqueue.append('n')"
3

下面的代码利用了Python的一些特性,给PDB模块添加了两个新命令。你只需要把给定的函数和它的调用放在一个单独的模块里,然后在开始调试之前导入这个模块。这样你就可以使用' disp'和' undisp'这两个命令来添加和撤销对变量的监视。

这个方法是通过修改Python的pdb模块来实现的,而这个模块是用纯Python写的。

# -*- coding: utf-8 -*-

def patch_pdb():
    import pdb

    def wrap(func):
        def new_postcmd(self, *args, **kw):
            result = func(self, *args, **kw)
            if hasattr(self, "curframe") and self.curframe and hasattr(self, "watch_list"):
                for arg in self.watch_list:
                    try:
                        print >> self.stdout, "%s: %s"% (arg, self._getval(arg)) + ", ", 
                    except: 
                        pass
                self.stdout.write("\n")
            return result #func(self, *args, **kw)

        return new_postcmd

    pdb.Pdb.postcmd = wrap(pdb.Pdb.postcmd)

    def do_disp(self, arg):
        if not hasattr(self, "watch_list"):
            self.watch_list = []
        self.watch_list.append(arg)

    pdb.Pdb.do_disp = do_disp

    def do_undisp(self, arg):
        if hasattr(self, "watch_list"):
            try:
                self.watch_list.remove(arg)
            except:
                pass

    pdb.Pdb.do_undisp = do_undisp

patch_pdb()

if __name__ == "__main__":
    # for testing
    import pdb; pdb.set_trace()
    a = 0
    for i in range(10):
        print i
        a += 2

不过,我只能让它显示变量在执行最后一个命令之前的状态。我尝试了一下,但修改bdb模块(这是Pdb的基础)似乎没有成功。你可以尝试更改pdb.Pdb、bdb.Bdb或cmd.Cmd中被wrap装饰的方法,找一个在调试的框架状态改变后被调用的方法。

撰写回答