web-dev-qa-db-ja.com

python Perlの$ DB :: single = 1と同様に機能する3.7PEP553より前のバージョンの条件付きデバッグブレークポイントワンライナー

python PEP 553 breakpoint()ユーティリティより前のバージョンでは、条件で無視できるブレークポイントを持つように(理想的には1ライナー)コードを追加するための推奨される方法は何ですか? (例:グローバルデバッグフラグまたはargs.debugフラグ)。

Perlでは、私は_$DB::single=1;1;_の単一行を使用することに慣れています。これは、コードに安全に残すことができ、明示的に_Perl code.pl_を呼び出さない限り、_Perl -d code.pl_の通常の実行に影響を与えないことがわかっています。例えば。:

_my $a = 1;
$DB::single=1;1; # breakpoint line
my $b = 2;
print "$a $b\n";
_

このコードを_Perl code.pl_として実行すると、完了するまで実行されます。このコードを_Perl -d code.pl_で実行すると、_my $b = 2;_が含まれているため、pdbはブレークポイント行で停止します(_1;_ステートメントの次の行の前ではありません)。 _$DB::single=1;_ステートメントの後のステートメント。

同様に、私が書く場合:

_my $debug = 1;
my $a = 1;
$DB::single=$debug;1; # first breakpoint line
my $b = 2;
$DB::single=$debug;1; # second breakpoint line
print "$a $b\n";
# [...] Lots more code sprinkled with more of these
$DB::single=$debug;1; # n'th breakpoint line
_

次に、_Perl -d code.pl_を実行できます。これは、最初のブレークポイント行で停止し、次にpdbセッションで停止します。他の場所で停止する必要がないことを確認したら、次を実行します。_$debug = 0_、次にpdb続行c。これにより、コードの2番目または他の同様のブレークポイント行で停止しなくなります。

python(PEP 553より前の2.xおよび3.x)で、理想的には1行のステートメントで同じことをどのように達成できますか?

私はPEP553を認識しており、_PYTHONBREAKPOINT=0 python3.7 code.py_を明示的に設定したり、breakpoint()行をコメントアウトしたりする手間を除けば、ここでの質問に対する解決策です。

私は次のようなオプションを考えました:

_import pdb; pdb.set_trace()
dummy=None;
_

pdb.set_trace()の下のステートメントは、Perlの_1;_の後の同じ行の_$DB::single=1;_と同じことを達成できるようにするためのものです。つまり、ブレークポイントを配置した場所でデバッガーを停止します。 、次のステートメントではなく。これは、コメントされたコードまたはドキュメントの大きなチャンクが間にある場合、デバッガーがブレークポイントから遠く離れた次のステートメントにジャンプしないようにするためです。

または次のような条件付き:

_if args.debug or debug:
    import pdb; pdb.set_trace()
    _debug=False; #args.debug=False
_

そのため、スクリプトのデバッグが完了したら、_args.debug=False_または_debug=False_を設定でき、コード内のこれらすべてのブレークポイントに触れる必要はありません。

16
719016

条件付きブレークポイントの設定

Perlと同じように、pythonを-dで実行して、デバッグフラグを設定できます。

$ python --help
[...]
-d     : debug output from parser; also PYTHONDEBUG=x
[...]

実行時にsys.flagsを介してその状態を確認できます:

$ python -d
Python 2.7.15+ (default, Nov 27 2018, 23:36:35) 
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.flags
sys.flags(debug=1, py3k_warning=0, division_warning=0, ...)
#         ^ there it is, right at the front

これにより、次のワンライナーでデバッグを有効にできます。

import pdb, sys; pdb.set_trace() if sys.flags[0] else None

デバッガーからの条件付きブレークポイントの無効化

この部分について

[...]他の場所で停止する必要がないことに満足したら、[何か]を実行します。これにより、コードの2行目または他の同様のブレークポイント行で停止しなくなります。

pythonは flags構造 の変更、またはそのインスタンスの作成さえ許可しないため、少し注意が必要です。

>>> import sys
>>> sys.flags.debug = 0                 # no mutating ...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: readonly attribute
>>> type(sys.flags)()                   # ... and no instanciating
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: cannot create 'sys.flags' instances

しかし、私がテストした限りでは、他のフラグを指定してpythonを実行しない限り、プログラムの他の動作を変更せずに、後続のトレースを非アクティブ化するために以下が機能します。

import sys; sys.flags = [0]*len(sys.flags)  # even fits onto a single line

前者が奇妙なバグにつながる場合に使用する必要があるもう少し堅牢なモンキーパッチの場合、次のようなものが必要になります。

def untrace():
  """Call this function in the pdb session to skip debug-only set_trace() calls"""
  import re
  import sys
  from collections import namedtuple  # has the same interface as struct sequence
  sys.flags = namedtuple(
    'sys_flags', 
    [m.group() for m in re.finditer(r'\w{2,}', repr(sys.flags)[10:-1])]
  )(0, *sys.flags[1:])

このステートメントcanは1行にまとめることができますが、多分少し多すぎます。この関数を使用する予定の.pyファイルに貼り付けるか、デバッグ中にインポートするutils.pyを用意して、その後a c(ontinue)は、プログラムの残りの部分を再度実行する必要があります。

(Pdb) import utils; utils.untrace()
(Pdb) c
7
Arne

現在のディレクトリにある.pdbrcファイルを使用する簡単な方法は次のとおりです。

t.py

def my_trace():
    global debug
    if debug:
        import pdb; pdb.set_trace()

debug = True
a= 1
my_trace()
b = 2
c = 3
my_trace()
d = 4

。pdbrc

r

セッション例

$ python t.py
--Return--
> [...]/t.py(12)<module>()
-> b = 2
(Pdb) p a
1
(Pdb) p b
*** NameError: name 'b' is not defined
(Pdb) !debug=False
(Pdb) c
$ 
4
Håkon Hægland