web-dev-qa-db-ja.com

pdbの変数をどのように監視しますか

pythonスクリプトをデバッグしています。gdbでメモリアドレスを監視できるように、変数を監視したいのですが、これを行う方法はありますか?

49
Nathaniel Flath

ブレークポイントをヒットしているときに変数を監視するには、commandsコマンドを使用できます。例えば。印刷some_variableブレークポイント#1にヒットしたとき( pdb docの標準的な例 )。

(Pdb) commands 1
(com) print some_variable
(com) end
(Pdb)

Python 3の更新

(Pdb) commands 1
(com) print(some_variable)
(com) end
(Pdb)

また、conditionコマンドを使用して、変数が特定の値をとるときにのみブレークポイントにヒットするようにすることができます。

例えば:

(Pdb) condition 1 some_variable==some_value
23
dnozay

pdbを使用してこれを行うための非常にハックな方法を次に示します。これらのコマンドは、~/.pdbrcpdbを使用するたびに自動的にロードします。

!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"])

これにより、nextwatchstepwatchの2つのコマンドが追加されます。これらはそれぞれ変数名varnameを引数として取ります。可能であればvarnameの現在のフレームのローカル変数の浅いコピーを作成し、その名前が指すものが変更されるまでnextまたはstepをそれぞれ実行し続けます。

これはCPython 2.7.2で動作しますが、いくつかのpdb内部に依存しているため、おそらく他の場所で壊れます。

22
Michael Hoffman

Python 3の場合:

使用できます表示pdbの機能

ブレークポイントに到達したら、単に入力します

ipdb>displayexpression

例:

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> 

ご覧のとおり、ディスプレイを入力するたびに、すべてのウォッチ(式)が出力されます。組み込み関数undisplayを使用して、特定のウォッチを削除できます。

pp expressionを使用して、式をきれいに印刷することもできます(非常に便利です)

15
DmitrySemenov

可能な解決策は、 pdb ++ を使用することです。

_pip install pdbpp
_

次に、デコレータ_@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
_

ここで、pdbは、Fooオブジェクトの属性barを変更すると中断します。

注意事項
基礎となる___setattr___- methodの呼び出しのみがブレークポイントをトリガーします。これは、_f.bar = 'XYZ'_およびsetattr(f, 'XYZ')は機能するが、bar-オブジェクトを操作してもブレークポイントがトリガーされないことを意味します。

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

f.bar = 2
f.bar += 5      # will trigger breakpoint
_

注:_@break_on_setattr_は、標準のpdb- moduleの一部ではありません。 pdbは、pdbpp- packageによってオーバーライド/モンキーパッチされます。

pdb.set_trace()の後に、既存のオブジェクトを(そのクラスを介して)ラップすることもできます。

_(Pdb++) import pdb
(Pdb++) pdb.break_on_setattr('tree_id')(self.__class__)
(Pdb++) continue
_
13
qff