你如何在pdb中观察变量

Nat*_*ath 52 python pdb

我正在调试一个python脚本,我想看一个变量来进行更改(很像你可以在gdb中观看内存地址).有没有办法做到这一点?

dno*_*zay 25

要在遇到断点时观察变量,可以使用该commands命令.例如,some_variable在击中断点#1时打印(来自pdbdoc的规范示例).

(Pdb) commands 1
(com) print some_variable
(com) end
(Pdb)
Run Code Online (Sandbox Code Playgroud)

Python 3的更新

(Pdb) commands 1
(com) print(some_variable)
(com) end
(Pdb)
Run Code Online (Sandbox Code Playgroud)

此外,您可以使用该condition命令确保仅在变量获取特定值时才会触发断点.

例如:

(Pdb) condition 1 some_variable==some_value
Run Code Online (Sandbox Code Playgroud)

  • 虽然它很有用,但它并没有直接回答这个问题,它想要观察变量的变化,然后打破这些变化,而不仅仅是在预设的断点处查看变量的状态. (5认同)

Mic*_*man 22

这是一个真正的hacky方式来做到这一点pdb.~/.pdbrc每次使用时,这些命令都可以放入您的自动加载中pdb.

!global __currentframe, __stack; from inspect import currentframe as __currentframe, stack as __stack
!global __copy; from copy import copy as __copy
!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 _setup_watchpoint !global __key, __dict, __val; __key = '%1'; __dict = __currentframe().f_locals if __currentframe().f_locals.has_key(__key) else __currentframe().f_globals; __val = __copy(%1)

alias _nextwatch_internal next;; !if __dict[__key] == __val: __pdb.cmdqueue.append("_nextwatch_internal %1")
alias _stepwatch_internal step;; !if __dict[__key] == __val: __pdb.cmdqueue.append("_stepwatch_internal %1")

alias nextwatch __pdb.cmdqueue.extend(["_setup_watchpoint %1", "_nextwatch_internal"])
alias stepwatch __pdb.cmdqueue.extend(["_setup_watchpoint %1", "_stepwatch_internal"])
Run Code Online (Sandbox Code Playgroud)

这增加了两个命令,nextwatch并且stepwatch其中,每个取变量名VARNAME作为参数.如果可能的话,他们将为varname制作当前帧的局部变量的浅表副本,并继续执行nextstep分别直到该名称指向的变化.

这适用于CPython 2.7.2,但依赖于一些pdb内部因素,所以它可能会破坏其他地方.


Dmi*_*nov 16

对于Python 3:

您可以使用pdb的显示功能

一旦你点击了断点就输入了

ipdb> 显示 表达式

例:

ipdb> display instance
display instance: <AppUser: dmitry4>
ipdb> display instance.id
display instance.id: 9
ipdb> display instance.university
display instance.university: <University: @domain.com>

ipdb> display

Currently displaying:
instance.university: <University: @domain.com>
instance.id: 9
instance: <AppUser: dmitry4>
ipdb> 
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,每次键入显示时 - 它都会打印您的所有手表(表达式).您可以使用内置功能undisplay删除某些手表.

你也可以使用pp表达式来打印表达式(非常有用)

  • 如果您正在循环中观察变化,请添加“break &lt;lineno&gt;”,每次“继续”时,您都会看到显示内容。显示非常方便。 (2认同)

qff*_*qff 13

一种可能的解决方案是使用pdb ++:

pip install pdbpp
Run Code Online (Sandbox Code Playgroud)

然后用装饰器"标记"你想要观察的对象@pdb.break_on_setattr:

from pdb import break_on_setattr
@break_on_setattr('bar')
class Foo(object):
    pass

f = Foo()
f.bar = 42    # the program breaks here
Run Code Online (Sandbox Code Playgroud)

pdb将打破bar任何Foo对象上属性的任何更改.

注意事项
只有底层__setattr__方法的调用才会触发断点.这意味着f.bar = 'XYZ'并且setattr(f, 'XYZ')可以工作,但是操纵bar-object不会触发断点:

f.bar = []
f.bar.append(7) # will NOT trigger breakpoint

f.bar = 2
f.bar += 5      # will trigger breakpoint
Run Code Online (Sandbox Code Playgroud)

注意:@break_on_setattr不是标准pdb模块的一部分.pdbpdbpp-package 覆盖/修补猴子.

您还可以在以下情况之后包装现有对象(通过其类)pdb.set_trace():

(Pdb++) import pdb
(Pdb++) pdb.break_on_setattr('tree_id')(self.__class__)
(Pdb++) continue
Run Code Online (Sandbox Code Playgroud)