pdb-対話型デバッガー

pdb-対話型デバッガー


Pythonバージョン:1.4以降

pdbは、Pythonプログラム用の対話型デバッグ環境です。 プログラムの実行を一時停止する機能、変数値を表示する機能、プログラムが実際に実行していることを理解できるように行ごとのコードを実行する機能、および論理エラーを見つける機能が含まれます。

デバッガーの起動

pdbの使用を開始するには、インタプリタにデバッガを表示する方法とタイミングを伝える必要があります。 これを行うには、起動条件とデバッグ要件に応じていくつかの方法があります。

コマンドラインから

デバッガを使用する最も明白な方法は、コマンドラインから実行し、プログラムにパラメータを渡して、実行する内容を認識させることです。
# encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # class MyObj( object ): def __init__(self, num_loops): self.count = num_loops def go(self): for i in range(self.count): print i return if __name__ == '__main__' : MyObj(5).go() * This source code was highlighted with Source Code Highlighter .
  1. # encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # class MyObj( object ): def __init__(self, num_loops): self.count = num_loops def go(self): for i in range(self.count): print i return if __name__ == '__main__' : MyObj(5).go() * This source code was highlighted with Source Code Highlighter .
  2. # encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # class MyObj( object ): def __init__(self, num_loops): self.count = num_loops def go(self): for i in range(self.count): print i return if __name__ == '__main__' : MyObj(5).go() * This source code was highlighted with Source Code Highlighter .
  3. # encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # class MyObj( object ): def __init__(self, num_loops): self.count = num_loops def go(self): for i in range(self.count): print i return if __name__ == '__main__' : MyObj(5).go() * This source code was highlighted with Source Code Highlighter .
  4. # encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # class MyObj( object ): def __init__(self, num_loops): self.count = num_loops def go(self): for i in range(self.count): print i return if __name__ == '__main__' : MyObj(5).go() * This source code was highlighted with Source Code Highlighter .
  5. # encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # class MyObj( object ): def __init__(self, num_loops): self.count = num_loops def go(self): for i in range(self.count): print i return if __name__ == '__main__' : MyObj(5).go() * This source code was highlighted with Source Code Highlighter .
  6. # encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # class MyObj( object ): def __init__(self, num_loops): self.count = num_loops def go(self): for i in range(self.count): print i return if __name__ == '__main__' : MyObj(5).go() * This source code was highlighted with Source Code Highlighter .
  7. # encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # class MyObj( object ): def __init__(self, num_loops): self.count = num_loops def go(self): for i in range(self.count): print i return if __name__ == '__main__' : MyObj(5).go() * This source code was highlighted with Source Code Highlighter .
  8. # encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # class MyObj( object ): def __init__(self, num_loops): self.count = num_loops def go(self): for i in range(self.count): print i return if __name__ == '__main__' : MyObj(5).go() * This source code was highlighted with Source Code Highlighter .
  9. # encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # class MyObj( object ): def __init__(self, num_loops): self.count = num_loops def go(self): for i in range(self.count): print i return if __name__ == '__main__' : MyObj(5).go() * This source code was highlighted with Source Code Highlighter .
  10. # encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # class MyObj( object ): def __init__(self, num_loops): self.count = num_loops def go(self): for i in range(self.count): print i return if __name__ == '__main__' : MyObj(5).go() * This source code was highlighted with Source Code Highlighter .
  11. # encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # class MyObj( object ): def __init__(self, num_loops): self.count = num_loops def go(self): for i in range(self.count): print i return if __name__ == '__main__' : MyObj(5).go() * This source code was highlighted with Source Code Highlighter .
  12. # encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # class MyObj( object ): def __init__(self, num_loops): self.count = num_loops def go(self): for i in range(self.count): print i return if __name__ == '__main__' : MyObj(5).go() * This source code was highlighted with Source Code Highlighter .
  13. # encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # class MyObj( object ): def __init__(self, num_loops): self.count = num_loops def go(self): for i in range(self.count): print i return if __name__ == '__main__' : MyObj(5).go() * This source code was highlighted with Source Code Highlighter .
# encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # class MyObj( object ): def __init__(self, num_loops): self.count = num_loops def go(self): for i in range(self.count): print i return if __name__ == '__main__' : MyObj(5).go() * This source code was highlighted with Source Code Highlighter .

コマンドラインからデバッガーを起動すると、ソースがロードされ、最初に見つかった式で実行が停止します。 この場合、7行目のMyObjクラス定義を実行する前に停止します。

$ python -m pdb pdb_script.py
> .../pdb_script.py(7)<module>()
-> class MyObj(object):
(Pdb)

注:
通常、 pdbには、ファイルパスの出力時に各モジュールへのフルパスが含まれます。 例を簡潔にするために、デバッガーの出力では、これらのパスは...

通訳から

多くの開発者は、モジュール開発の初期段階でインタラクティブインタープリターを使用します。これにより、スタンドアロンスクリプトの作成に必要な保存/実行/繰り返しのサイクルを繰り返すことなく、より反復的に実験できるようになります。 対話型セッションからデバッガーを実行するには、 run ()またはruneval ()を使用します

$ python
Python 2.7 (r27:82508, Jul 3 2010, 21:12:11)
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pdb_script
>>> import pdb
>>> pdb.run('pdb_script.MyObj(5).go()')
> <string>(1)<module>()
(Pdb)


run()の引数は、Pythonインタープリターで実行できる文字列式です。 デバッガーはそれを解析し、最初の式が開始する直前に実行を停止します。 以下で説明するコマンドを使用して、実行をナビゲートおよび制御できます。

あなたのプログラムから

前の例は両方とも、プログラムの最初からデバッガーを開始したいという事実に基づいていました。 実行時にずっと後に問題が発生するより複雑なプロセスの場合、 set_trace ()を使用してプログラム内からデバッガーを実行する方が便利です。
  1. #!/ usr / bin / env python
  2. #エンコード:utf-8
  3. #Copyright(c)2010 Doug Hellmann。 無断複写・転載を禁じます。
  4. インポートpdb
  5. クラス MyObj( オブジェクト ):
  6. def __init __(self、num_loops):
  7. self.count = num_loops
  8. def go(self):
  9. 範囲内のi(self.count):
  10. pdb.set_trace()
  11. 印刷する
  12. 帰る
  13. __name__ == '__main__'の場合
  14. MyObj(5).go()

16行目で、テストスクリプトはデバッガーを呼び出します。

$ python ./pdb_set_trace.py
> .../pdb_set_trace.py(17)go()
-> print i
(Pdb)


set_trace()はPythonの単なる関数なので、プログラムの実行中にいつでも呼び出すことができます。 これにより、例外を処理するときや、制御式の特別な分岐など、プログラム内で一般的な条件に応じて、デバッグモードに入ることができます。

故障後

プログラムの完了後のデバッグは、事後デバッグと呼ばれます。 pdbは、 pm ()およびpost_mortem ()関数を使用してこのようなデバッグをサポートします。
  1. #!/ usr / bin / env python
  2. #エンコード:utf-8
  3. #Copyright(c)2010 Doug Hellmann。 すべての権利を留保します。
  4. クラス MyObj( オブジェクト ):
  5. def __init __(self、num_loops):
  6. self.count = num_loops
  7. def go(self):
  8. 範囲内のi(self.num_loops):
  9. 印刷する
  10. 帰る

ここでは、13行目で無効なフィールド名がAttributeError例外をスローし、実行が停止します。 pm()は、インタラクティブトレースバックを見て、例外が発生したスタックフレームでデバッガーを起動します。

$ python
Python 2.7 (r27:82508, Jul 3 2010, 21:12:11)
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from pdb_post_mortem import MyObj
>>> MyObj(5).go()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "pdb_post_mortem.py", line 13, in go
for i in range(self.num_loops):
AttributeError: 'MyObj' object has no attribute 'num_loops'
>>> import pdb
>>> pdb.pm()
> .../pdb_post_mortem.py(13)go()
-> for i in range(self.num_loops):
(Pdb)


デバッガー管理

デバッガーとの相互作用は、スタックのナビゲート、変数の値の表示と変更、デバッガーによるプログラムの実行方法の制御を可能にする小さなコマンド言語に要約されます。 デバッガーはreadlineを使用してコマンドを読み取ります。 空の行を入力すると、ソースを表示する場合を除き、前のコマンドが繰り返されます。

コールスタックナビゲーション

デバッガーの作業中はいつでも、 where (または単にw )を使用して現在実行している行と呼び出しスタック内の場所を指定できます。 この場合、go()メソッドのpdb_set_trace.pyモジュール行17。

$ python pdb_set_trace.py
> .../pdb_set_trace.py(17)go()
-> print i
(Pdb) where
.../pdb_set_trace.py(21)<module>()
-> MyObj(5).go()
> .../pdb_set_trace.py(17)go()
-> print i


現在の場所のコンテキストを表示するには、 リストl )を使用します

(Pdb) list
12 self.count = num_loops
13
14 def go(self):
15 for i in range(self.count):
16 pdb.set_trace()
17 -> print i
18 return
19
20 if __name__ == '__main__':
21 MyObj(5).go()
[EOF]
(Pdb)


デフォルトでは、現在の行の周囲に11行(上5行と下5行)が表示されます。 listが単一の引数で呼び出されると、現在の行ではなく、指定された行に隣接する11行が表示されます。

(Pdb) list 14
9 class MyObj(object):
10
11 def __init__(self, num_loops):
12 self.count = num_loops
13
14 def go(self):
15 for i in range(self.count):
16 pdb.set_trace()
17 -> print i
18 return
19


リスト2つの引数を渡すと、それらは表示される最初と最後の行として処理されます。

(Pdb) list 5, 19
5 #
6
7 import pdb
8
9 class MyObj(object):
10
11 def __init__(self, num_loops):
12 self.count = num_loops
13
14 def go(self):
15 for i in range(self.count):
16 pdb.set_trace()
17 -> print i
18 return
19


upおよびdownを使用て呼び出しスタックをナビゲートします。 up(短いu )は、スタック上の以前の呼び出しに移動します。 down(またはd )は、より深い課題に引き継がれます。

(Pdb) up
> .../pdb_set_trace.py(21)<module>()
-> MyObj(5).go()

(Pdb) down
> .../pdb_set_trace.py(17)go()
-> print i


スタックに沿って移動するたびに、デバッガーは現在の場所をwhereと同じ形式で表示します。

スタック上の変数を表示する

実行可能関数にローカルな値やグローバルステータス情報など、変数のセットがスタックの各フレームに関連付けられています。 pdbは、これらの変数の内容を表示するいくつかの方法を提供します。
  1. #!/ usr / bin / env python
  2. #エンコード:utf-8
  3. #Copyright(c)2010 Doug Hellmann。 無断複写・転載を禁じます。
  4. インポートpdb
  5. def recursive_function(n = 5、出力= '印刷される' ):
  6. n> 0の場合
  7. 再帰関数(n-1)
  8. その他
  9. pdb.set_trace()
  10. 印刷出力
  11. 帰る
  12. __name__ == '__main__'の場合
  13. recursive_function()


argsコマンド(別名a )は、現在のフレームでアクティブな関数のすべての引数を表示します。 また、この例では再帰関数を使用して、where出力でのディープスタックの外観を示しています。

$ python pdb_function_arguments.py
> .../pdb_function_arguments.py(14)recursive_function()
-> return
(Pdb) where
.../pdb_function_arguments.py(17)<module>()
-> recursive_function()
.../pdb_function_arguments.py(11)recursive_function()
-> recursive_function(n-1)
.../pdb_function_arguments.py(11)recursive_function()
-> recursive_function(n-1)
.../pdb_function_arguments.py(11)recursive_function()
-> recursive_function(n-1)
.../pdb_function_arguments.py(11)recursive_function()
-> recursive_function(n-1)
.../pdb_function_arguments.py(11)recursive_function()
-> recursive_function(n-1)
> .../pdb_function_arguments.py(14)recursive_function()
-> return

(Pdb) args
n = 0
output = to be printed

(Pdb) up
> .../pdb_function_arguments.py(11)recursive_function()
-> recursive_function(n-1)

(Pdb) args
n = 1
output = to be printed

(Pdb)


pコマンドは、引数で渡された式を実行し、結果を出力します。 print文を使用することもできますが、実行の代わりにデバッガーコマンドとしてPythonインタープリターに渡されます。

(Pdb) pn
1

(Pdb) print n
1


同様に、 で始まる式 すぐにPythonインタープリターに送信して実行します。 この機能を使用して、変数の変更を含む任意のPythonコマンドを実行できます。 この例では、デバッガーがプログラムの実行を継続できるようにする前に、出力の値が変更されます。 set_trace()の後の次の呼び出しは、出力を出力し、変更された値を表示します。

$ python pdb_function_arguments.py
> .../pdb_function_arguments.py(14)recursive_function()
-> print output

(Pdb) !output
'to be printed'

(Pdb) !output='changed value'

(Pdb) continue
changed value


ネストされたデータ構造や大きなデータ構造など、より複雑な値の場合は、「きれいな」出力にpp (きれいな印刷)を使用します。 このプログラムは、ファイルから数行のテキストを読み取ります。
  1. #!/ usr / bin / env python
  2. #エンコード:utf-8
  3. #Copyright(c)2010 Doug Hellmann。 無断複写・転載を禁じます。
  4. インポートpdb
  5. f として open( 'lorem.txt''rt'を使用
  6. lines = f.readlines()
  7. pdb.set_trace()

pを含む行の出力は読みにくい 彼は不自然に容認されています。 ppは、出力前にpprintを使用して値をフォーマットします。

$ python pdb_pp.py
--Return--
> .../pdb_pp.py(12)<module>()->None
-> pdb.set_trace()
(Pdb) p lines
['Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec\n', 'egestas, enim
et consectetuer ullamcorper, lectus ligula rutrum leo, a\n', 'elementum elit tortor
eu quam.\n']

(Pdb) pp lines
['Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec\n',
'egestas, enim et consectetuer ullamcorper, lectus ligula rutrum leo, a\n',
'elementum elit tortor eu quam.\n']

(Pdb)


プログラムステップ

プログラムの一時停止中にスタックを上下にナビゲートすることに加えて、デバッガーが呼び出された場所からステップで実行を継続することもできます。
  1. #!/ usr / bin / env python
  2. #エンコード:utf-8
  3. #Copyright(c)2010 Doug Hellmann。 すべての権利を留保します。
  4. インポートpdb
  5. def f(n):
  6. 範囲(n)のiの場合:
  7. j = i * n
  8. 印刷i、j
  9. 帰る
  10. __name__ == '__main__'の場合
  11. pdb.set_trace()
  12. f(5)

stepを使用して現在の行を実行し、次の実行可能ポイント(呼び出された関数内の最初の式、または現在の関数の次の行)の前で停止します。

$ python pdb_step.py
> /Users/dhellmann/Documents/PyMOTW/src.pdb/PyMOTW/pdb/pdb_step.py(17)<module>()
-> f(5)


インタープリターはset_trace()を呼び出して停止し、制御をデバッガーに転送します。 stepへの最初の呼び出しは、f()を呼び出します。

(Pdb) step
--Call--
> .../pdb_step.py(9)f()
-> def f(n):


もう一度、ステップ、およびf()関数の最初の行が現在の行になり、ループの実行が開始されます。

(Pdb) step
> .../pdb_step.py(10)f()
-> for i in range(n):


再度ステップを実行すると、ループ内の最初の行に到達します。ここで、jが決定されます。

(Pdb) step
> /Users/dhellmann/Documents/PyMOTW/src.pdb/PyMOTW/pdb/pdb_step.py(11)f()
-> j = i * n
(Pdb) pi
0


iの値は0なので、このステップの後、jの値も0になります。

(Pdb) step
> /Users/dhellmann/Documents/PyMOTW/src.pdb/PyMOTW/pdb/pdb_step.py(12)f()
-> print i, j

(Pdb) pj
0

(Pdb)


エラーの箇所まで多くのコードを処理する必要がある場合、または関数が繰り返し呼び出される場合、何度も繰り返し歩くのは面倒です。
  1. #!/ usr / bin / env python
  2. #エンコード:utf-8
  3. #Copyright(c)2010 Doug Hellmann。 無断複写・転載を禁じます。
  4. インポートpdb
  5. def calc(i、n):
  6. j = i * n
  7. リターン j
  8. def f(n):
  9. 範囲(n)のiの場合:
  10. j =計算(i、n)
  11. 印刷i、j
  12. 帰る
  13. __name__ == '__main__'の場合
  14. pdb.set_trace()
  15. f(5)

この例では、calc()に問題はないため、f()のループで呼び出されるたびにすべての行を反復処理し、有用な出力のみを詰まらせ、実行時にすべてのcalc()行を表示します。

$ python pdb_next.py
> .../pdb_next.py(21)<module>()
-> f(5)
(Pdb) step
--Call--
> .../pdb_next.py(13)f()
-> def f(n):

(Pdb) step
> .../pdb_next.py(14)f()
-> for i in range(n):

(Pdb) step
> .../pdb_next.py(15)f()
-> j = calc(i, n)

(Pdb) step
--Call--
> .../pdb_next.py(9)calc()
-> def calc(i, n):

(Pdb) step
> .../pdb_next.py(10)calc()
-> j = i * n

(Pdb) step
> .../pdb_next.py(11)calc()
-> return j

(Pdb) step
--Return--
> .../pdb_next.py(11)calc()->0
-> return j

(Pdb) step
> .../pdb_next.py(16)f()
-> print i, j

(Pdb) step
0 0


次のコマンドはステップに似ていますが、現在の式によって呼び出される関数の一部ではありません。 その結果、このコマンドの実行後、デバッガーは現在の関数の次の式に進みます。

> .../pdb_next.py(14)f()
-> for i in range(n):
(Pdb) step
> .../pdb_next.py(15)f()
-> j = calc(i, n)

(Pdb) next
> .../pdb_next.py(16)f()
-> print i, j

(Pdb)


u ntilコマンドはnextのようなもので、現在の関数の下位(現在の関数よりも大きい数)の行に到達するまで実行を継続するだけです。 これは、たとえば、untilを使用してループを終了できることを意味します。

$ python pdb_next.py
> .../pdb_next.py(21)<module>()
-> f(5)
(Pdb) step
--Call--
> .../pdb_next.py(13)f()
-> def f(n):

(Pdb) step
> .../pdb_next.py(14)f()
-> for i in range(n):

(Pdb) step
> .../pdb_next.py(15)f()
-> j = calc(i, n)

(Pdb) next
> .../pdb_next.py(16)f()
-> print i, j

(Pdb) until
0 0
1 5
2 10
3 15
4 20
> .../pdb_next.py(17)f()
-> return

(Pdb)


untilまで、現在の行は16-ループの最後の行でした。 まで実行した後、実行は17行目に達し、サイクルが完了しました。

returnは、関数の一部をスキップする別の方法です。 現在の関数からの復帰が実行される瞬間まで実行を継続し、プログラムを一時停止します。 これにより、関数から戻る前に戻り値を確認する時間が与えられます。

$ python pdb_next.py
> .../pdb_next.py(21)<module>()
-> f(5)
(Pdb) step
--Call--
> .../pdb_next.py(13)f()
-> def f(n):

(Pdb) step
> .../pdb_next.py(14)f()
-> for i in range(n):

(Pdb) return
0 0
1 5
2 10
3 15
4 20
--Return--
> .../pdb_next.py(17)f()->None
-> return

(Pdb)


ブレークポイント

プログラムがさらに大きくなると、nextやuntilを使用しても遅くなり、退屈になります。 プログラムを1行ずつステップスルーする代わりに、より良い解決策があります。中断する必要がある時点に達するまで、プログラムを正常に実行できます。 set_trace()を使用してデバッガーを起動できますが、これはプログラムを1か所で停止する場合にのみ機能します。 より便利な解決策は、デバッガーでプログラム全体を実行することですが、ブレークポイントの使用を停止する場所を事前に指示します。 デバッガーはプログラムの実行を監視し、ブレークポイントで記述された場所に到達すると、指定された行の前で実行を停止します。
  1. #!/ usr / bin / env python
  2. #エンコード:utf-8
  3. #Copyright(c)2010 Doug Hellmann。 無断複写・転載を禁じます。
  4. def calc(i、n):
  5. j = i * n
  6. 印刷'j =' 、j
  7. j> 0の場合
  8. 「ポジティブ!」
  9. リターン j
  10. def f(n):
  11. 範囲(n)のiの場合:
  12. print 'i =' 、i
  13. j =計算(i、n)
  14. 帰る
  15. __name__ == '__main__'の場合
  16. f(5)

breakコマンドは、ブレークポイントを設定するためのいくつかのオプションを受け入れます。 実行を停止する行番号、ファイル、または関数を指定できます。 現在のファイルの特定の行にブレークポイントを設定するには、 break linenoを使用します。

$ python -m pdb pdb_break.py
> .../pdb_break.py(7)<module>()
-> def calc(i, n):
(Pdb) break 11
Breakpoint 1 at .../pdb_break.py:11

(Pdb) continue
i = 0
j = 0
i = 1
j = 5
> .../pdb_break.py(11)calc()
-> print 'Positive!'

(Pdb)

continueコマンドは、次のブレークポイントまでプログラムの実行を続けるようデバッガーに指示します。 この場合、f()のループの最初の反復はパスし、2番目の反復でcalc()で停止します。

行番号の代わりに名前を指定することにより、関数の最初の行にブレークポイントを設定することもできます。 次の例は、calc()関数にブレークポイントを追加するとどうなるかを示しています。

$ python -m pdb pdb_break.py
> .../pdb_break.py(7)<module>()
-> def calc(i, n):
(Pdb) break calc
Breakpoint 1 at .../pdb_break.py:7

(Pdb) continue
i = 0
> .../pdb_break.py(8)calc()
-> j = i * n

(Pdb) where
.../pdb_break.py(21)<module>()
-> f(5)
.../pdb_break.py(17)f()
-> j = calc(i, n)
> .../pdb_break.py(8)calc()
-> j = i * n

(Pdb)


別のファイルにブレークポイントを指定するには、行番号または関数名の前にファイル名を付けます。
  1. #!/ usr / bin / env python
  2. #エンコード:utf-8
  3. #Copyright(c)2010 Doug Hellmann。 無断複写・転載を禁じます。
  4. pdb_break import f から
  5. f(5)

ここでは、メインプログラムpdb_break_remote.pyを起動した後、pdb_break.pyの11行目にブレークポイントを設定します。

$ python -m pdb pdb_break_remote.py
> .../pdb_break_remote.py(7)<module>()
-> from pdb_break import f
(Pdb) break pdb_break.py:11
Breakpoint 1 at .../pdb_break.py:11

(Pdb) continue
i = 0
j = 0
i = 1
j = 5
> .../pdb_break.py(11)calc()
-> print 'Positive!'

(Pdb)


ファイル名は、ソースへの絶対パス、またはsys.pathで使用可能なファイルへの相対パスにすることができます。

現在設定されているブレークポイントを表示するには、引数なしでbreakを使用します。 出力には、各ブレークポイントのファイルと行番号、およびヒットした回数に関する情報が含まれます。

$ python -m pdb pdb_break.py
> .../pdb_break.py(7)<module>()
-> def calc(i, n):
(Pdb) break 11
Breakpoint 1 at .../pdb_break.py:11

(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../pdb_break.py:11

(Pdb) continue
i = 0
j = 0
i = 1
j = 5
> .../pdb/pdb_break.py(11)calc()
-> print 'Positive!'

(Pdb) continue
Positive!
i = 2
j = 10
> .../pdb_break.py(11)calc()
-> print 'Positive!'

(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../pdb_break.py:11
breakpoint already hit 2 times

(Pdb)


ブレークポイント管理

追加された各ブレークポイントには、数値識別子が割り当てられます。 これらの識別子は、ブレークポイントをインタラクティブに有効化、無効化、および削除するために使用されます。

disableでブレークポイントをオフにすると、この行に達したときに停止する必要がないことがデバッガーに通知されます。 ブレークポイントは記憶されますが、無視されます。

$ python -m pdb pdb_break.py
> .../pdb_break.py(7)<module>()
-> def calc(i, n):
(Pdb) break calc
Breakpoint 1 at .../pdb_break.py:7

(Pdb) break 11
Breakpoint 2 at .../pdb_break.py:11

(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../pdb_break.py:7
2 breakpoint keep yes at .../pdb_break.py:11

(Pdb) disable 1

(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep no at .../pdb_break.py:7
2 breakpoint keep yes at .../pdb_break.py:11

(Pdb) continue
i = 0
j = 0
i = 1
j = 5
> .../pdb_break.py(11)calc()
-> print 'Positive!'

(Pdb)


次の例のデバッグセッションでは、プログラムに2つのブレークポイントを設定し、そのうちの1つを無効にします。 プログラムは、残りのブレークポイントに到達するまで実行され、その後、別のブレークポイントがオンになり、実行が継続されます。

$ python -m pdb pdb_break.py
> .../pdb_break.py(7)<module>()
-> def calc(i, n):
(Pdb) break calc
Breakpoint 1 at .../pdb_break.py:7

(Pdb) break 16
Breakpoint 2 at .../pdb_break.py:16

(Pdb) disable 1

(Pdb) continue
> .../pdb_break.py(16)f()
-> print 'i =', i

(Pdb) list
11 print 'Positive!'
12 return j
13
14 def f(n):
15 for i in range(n):
16 B-> print 'i =', i
17 j = calc(i, n)
18 return
19
20 if __name__ == '__main__':
21 f(5)

(Pdb) continue
i = 0
j = 0
> .../pdb_break.py(16)f()
-> print 'i =', i

(Pdb) list
11 print 'Positive!'
12 return j
13
14 def f(n):
15 for i in range(n):
16 B-> print 'i =', i
17 j = calc(i, n)
18 return
19
20 if __name__ == '__main__':
21 f(5)

(Pdb) pi
1

(Pdb) enable 1

(Pdb) continue
i = 1
> .../pdb_break.py(8)calc()
-> j = i * n

(Pdb) list
3 #
4 # Copyright (c) 2010 Doug Hellmann. All rights reserved.
5 #
6
7 B def calc(i, n):
8 -> j = i * n
9 print 'j =', j
10 if j > 0:
11 print 'Positive!'
12 return j
13

(Pdb)


リスト出力でBが示される前の行は、ブレークポイントがインストールされているプログラムの場所を示しています(行9および18)。

clearを使用して、ブレークポイントを完全に削除します。

$ python -m pdb pdb_break.py
> .../pdb_break.py(7)<module>()
-> def calc(i, n):
(Pdb) break calc
Breakpoint 1 at .../pdb_break.py:7

(Pdb) break 11
Breakpoint 2 at .../pdb_break.py:11

(Pdb) break 16
Breakpoint 3 at .../pdb_break.py:16

(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../pdb_break.py:7
2 breakpoint keep yes at .../pdb_break.py:11
3 breakpoint keep yes at .../pdb_break.py:16

(Pdb) clear 2
Deleted breakpoint 2

(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../pdb_break.py:7
3 breakpoint keep yes at .../pdb_break.py:16

(Pdb)


残りのブレークポイントは識別子を保持し、番号は変更されません。

一時的なブレークポイント

一時的なブレークポイントは、最初のヒット後に自動的にクリアされます。 ただし、一時的なブレークポイントを使用すると、従来のブレークポイントと同様に、プログラム実行の特定のポイントにすばやく到達できます。 すぐにクリーニングされるため、プログラムのこの部分が繰り返し実行されても、それ以上の作業を妨げることはありません。

$ python -m pdb pdb_break.py
> .../pdb_break.py(7)<module>()
-> def calc(i, n):
(Pdb) tbreak 11
Breakpoint 1 at .../pdb_break.py:11

(Pdb) continue
i = 0
j = 0
i = 1
j = 5
Deleted breakpoint 1
> .../pdb_break.py(11)calc()
-> print 'Positive!'

(Pdb) break

(Pdb) continue
Positive!
i = 2
j = 10
Positive!
i = 3
j = 15
Positive!
i = 4
j = 20
Positive!
The program finished and will be restarted
> .../pdb_break.py(7)<module>()
-> def calc(i, n):

(Pdb)


実行が初めて11行目に達した後、ブレークポイントが削除され、プログラムは最後までノンストップで実行されます。

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

ルールをブレークポイントに適用して、条件が満たされた場合にのみプログラムの実行が停止するようにすることもできます。 条件付きブレークポイントを使用すると、ブレークポイントを手動でオンまたはオフにするよりも、ストップをより細かく制御できます。

条件付きブレークポイントは、2つの方法のいずれかで設定できます。 1つ目は、breakを使用してブレークポイントを作成するときの条件を指定することです。

$ python -m pdb pdb_break.py
> .../pdb_break.py(7)<module>()
-> def calc(i, n):
(Pdb) break 9, j>0
Breakpoint 1 at .../pdb_break.py:9

(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../pdb_break.py:9
stop only if j>0

(Pdb) continue
i = 0
j = 0
i = 1
> .../pdb_break.py(9)calc()
-> print 'j =', j

(Pdb)


条件引数は、ブレークポイントが定義されているスタックのフレームに表示される変数名を使用した式でなければなりません。 式が値Trueに減少すると、プログラムはブレークポイントで停止します。

conditionコマンドを使用して、既存のブレークポイントに条件を適用することもできます。 引数-ブレークポイントIDおよび式。

$ python -m pdb pdb_break.py
> .../pdb_break.py(7)<module>()
-> def calc(i, n):
(Pdb) break 9
Breakpoint 1 at .../pdb_break.py:9

(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../pdb_break.py:9

(Pdb) condition 1 j>0

(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../pdb_break.py:9
stop only if j>0

(Pdb)


ブレークポイントを無視する

多くのサイクルまたは再帰呼び出しを伴うプログラムは、各呼び出しとブレークポイントを表示するのではなく、プログラム実行のいくつかの段階を「スクロール」することでデバッグが容易になることがよくあります。 ignoreコマンドは、デバッガーにいくつかのブレークポイントをスキップするように指示します。 ブレークポイントを通過するたびに、無視カウンターが減少します。 0に達すると、ブレークポイントが再びアクティブになります。

$ python -m pdb pdb_break.py
> .../pdb_break.py(7)<module>()
-> def calc(i, n):
(Pdb) break 17
Breakpoint 1 at .../pdb_break.py:17

(Pdb) continue
i = 0
> .../pdb_break.py(17)f()
-> j = calc(i, n)

(Pdb) next
j = 0
> .../pdb_break.py(15)f()
-> for i in range(n):

(Pdb) ignore 1 2
Will ignore next 2 crossings of breakpoint 1.

(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../pdb_break.py:17
ignore next 2 hits
breakpoint already hit 1 time

(Pdb) continue
i = 1
j = 5
Positive!
i = 2
j = 10
Positive!
i = 3
> .../pdb_break.py(17)f()
-> j = calc(i, n)

(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../pdb_break.py:17
breakpoint already hit 4 times


カウンターを明示的にゼロに設定すると、ブレークポイントがすぐにアクティブになります。

$ python -m pdb pdb_break.py
> .../pdb_break.py(7)<module>()
-> def calc(i, n):
(Pdb) break 17
Breakpoint 1 at .../pdb_break.py:17

(Pdb) ignore 1 2
Will ignore next 2 crossings of breakpoint 1.

(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../pdb_break.py:17
ignore next 2 hits

(Pdb) ignore 1 0
Will stop next time breakpoint 1 is reached.

(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../pdb_break.py:17


ブレークポイントアクションの起動

インタラクティブモードに加えて、 pdbは単純なスクリプトをサポートしています。 コマンドを使用すると、ブレークポイントに到達したときに実行されるPython式など、インタープリターの一連のアクションを決定できます。 行引数番号でコマンドを実行すると、デバッガープロンプトは(com)に変わります。 コマンドを1つずつ入力し、最後にendを入力してスクリプトを保存し、デバッガーのメインモードに戻ります。

$ python -m pdb pdb_break.py
> .../pdb_break.py(7)<module>()
-> def calc(i, n):
(Pdb) break 9
Breakpoint 1 at .../pdb_break.py:9

(Pdb) commands 1
(com) print 'debug i =', i
(com) print 'debug j =', j
(com) print 'debug n =', n
(com) end

(Pdb) continue
i = 0
debug i = 0
debug j = 0
debug n = 5
> .../pdb_break.py(9)calc()
-> print 'j =', j

(Pdb) continue
j = 0
i = 1
debug i = 1
debug j = 5
debug n = 5
> .../pdb_break.py(9)calc()
-> print 'j =', j

(Pdb)


この関数は、多くのデータ構造、変数を使用するコードのデバッグに特に役立ちます。 各ブレークポイントで手動で行うのではなく、すべての値を自動的に表示できます。

進捗管理

ジャンプコマンドを使用すると、ソースコードを変更することなく、プログラムの実行をオンザフライで制御できます。 プログラムの一部を前方にジャンプしてコードの実行を回避したり、後方にジャンプして再度実行したりできます。 数字のリストを生成する簡単なプログラム。
  1. #!/ usr / bin / env python
  2. #エンコード:utf-8
  3. #Copyright(c)2010 Doug Hellmann。 無断複写・転載を禁じます。
  4. def f(n):
  5. 結果= []
  6. j = 0
  7. 範囲(n)のiの場合:
  8. j = i * n + j
  9. j + = n
  10. result.append(j)
  11. 結果を返す
  12. __name__ == '__main__'の場合
  13. プリントf(5)

介入なしで実行すると、出力は5で割り切れる数字の増加シーケンスです。

$ python pdb_jump.py

[5, 15, 30, 50, 75]


進む

前方に移動すると、前のコマンドを実行せずに、現在の行よりも遠いポイントに実行が転送されます。 以下の例の13行目をスキップすると、jの値は増加せず、それに依存するすべての後続の値はわずかに小さくなります。

$ python -m pdb pdb_jump.py
> .../pdb_jump.py(7)<module>()
-> def f(n):
(Pdb) break 12
Breakpoint 1 at .../pdb_jump.py:12

(Pdb) continue
> .../pdb_jump.py(12)f()
-> j += n

(Pdb) pj
0

(Pdb) step
> .../pdb_jump.py(13)f()
-> result.append(j)

(Pdb) pj
5

(Pdb) continue
> .../pdb_jump.py(12)f()
-> j += n

(Pdb) jump 13
> .../pdb_jump.py(13)f()
-> result.append(j)

(Pdb) pj
10

(Pdb) disable 1

(Pdb) continue
[5, 10, 25, 45, 70]

The program finished and will be restarted
> .../pdb_jump.py(7)<module>()
-> def f(n):
(Pdb)


戻る

遷移は、プログラムの実行を既に実行された式に転送して再起動することもできます。 ここで、jの値がもう一度増分されるため、結果として数値が通常よりも大きくなります。

$ python -m pdb pdb_jump.py
> .../pdb_jump.py(7)<module>()
-> def f(n):
(Pdb) break 13
Breakpoint 1 at .../pdb_jump.py:13

(Pdb) continue
> .../pdb_jump.py(13)f()
-> result.append(j)

(Pdb) pj
5

(Pdb) jump 12
> .../pdb_jump.py(12)f()
-> j += n

(Pdb) continue
> .../pdb_jump.py(13)f()
-> result.append(j)

(Pdb) pj
10

(Pdb) disable 1

(Pdb) continue
[10, 20, 35, 55, 80]

The program finished and will be restarted
> .../pdb_jump.py(7)<module>()
-> def f(n):
(Pdb)

禁断の交差点

計算の流れを制御するいくつかの式の「から」および「から」への遷移は危険またはあいまいであるため、デバッガーによって禁止されています。
  1. #!/ usr / bin / env python
  2. #エンコード:utf-8
  3. #Copyright(c)2010 Doug Hellmann。 無断複写・転載を禁じます。
  4. def f(n):
  5. n <0の場合
  6. ValueErrorを発生させます( 'Invalid n:%s' %n)
  7. 結果= []
  8. j = 0
  9. 範囲(n)のiの場合:
  10. j = i * n + j
  11. j + = n
  12. result.append(j)
  13. 結果を返す
  14. __name__ == '__main__'の場合
  15. 試してください
  16. プリントf(5)
  17. 最後に
  18. 印刷「常に印刷」
  19. 試してください
  20. プリントf(-5)
  21. を除く:
  22. 「エラーが発生しました」を印刷
  23. その他
  24. 「エラーなし」を印刷
  25. 「最後のステートメント」を印刷

関数の中に入ることはできますが、もしそうすると、引数は定義されず、コードは動作しません。

$ python -m pdb pdb_no_jump.py
> .../pdb_no_jump.py(7)<module>()
-> def f(n):
(Pdb) break 21
Breakpoint 1 at .../pdb_no_jump.py:21

(Pdb) jump 8
> .../pdb_no_jump.py(8)<module>()
-> if n < 0:

(Pdb) pn
*** NameError: NameError("name 'n' is not defined",)

(Pdb) args

(Pdb)


forループやtry:exceptステートメントなどのブロックの中に入ることはできません。

$ python -m pdb pdb_no_jump.py
> .../pdb_no_jump.py(7)<module>()
-> def f(n):
(Pdb) break 21
Breakpoint 1 at .../pdb_no_jump.py:21

(Pdb) continue
> .../pdb_no_jump.py(21)<module>()
-> print f(5)

(Pdb) jump 26
*** Jump failed: can't jump into the middle of a block

(Pdb)


finallyブロックのコードは実行する必要があるため、そこから飛び出すことはできません。
$ python -m pdb pdb_no_jump.py
> .../pdb_no_jump.py(7)<module>()
-> def f(n):
(Pdb) break 23
Breakpoint 1 at .../pdb_no_jump.py:23

(Pdb) continue
[5, 15, 30, 50, 75]
> .../pdb_no_jump.py(23)<module>()
-> print 'Always printed'

(Pdb) jump 25
*** Jump failed: can't jump into or out of a 'finally' block

(Pdb)


そして主な制限は、遷移がスタックの下部フレームによって制限されることです。 スタックを上って変数を表示する場合、このレベルで進行状況を変更することはできません。

$ python -m pdb pdb_no_jump.py
> .../pdb_no_jump.py(7)<module>()
-> def f(n):
(Pdb) break 11
Breakpoint 1 at .../pdb_no_jump.py:11

(Pdb) continue
> .../pdb_no_jump.py(11)f()
-> j = 0

(Pdb) where
/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/bdb.py(379)run()
-> exec cmd in globals, locals
<string>(1)<module>()
.../pdb_no_jump.py(21)<module>()
-> print f(5)
> .../pdb_no_jump.py(11)f()
-> j = 0

(Pdb) up
> .../pdb_no_jump.py(21)<module>()
-> print f(5)

(Pdb) jump 25
*** You can only jump within the bottom frame

(Pdb)


プログラムの再起動

デバッガがプログラムの最後に達すると、デバッガは自動的に再起動します。 デバッグモードを終了せずに、ブレークポイントやその他の設定を失うことなく、自分で再起動することもできます。
  1. #!/ usr / bin / env python
  2. #エンコード:utf-8
  3. #Copyright(c)2010 Doug Hellmann。 無断複写・転載を禁じます。
  4. インポートシステム
  5. def f():
  6. print 'コマンドライン引数:' 、sys.argv
  7. 帰る
  8. __name__ == '__main__'の場合
  9. f()

上記のプログラムをデバッガーで実行すると、コマンドラインで他の引数が渡されなかったため、スクリプトの名前が出力されます。

$ python -m pdb pdb_run.py
> .../pdb_run.py(7)<module>()
-> import sys
(Pdb) continue

Command line args: ['pdb_run.py']
The program finished and will be restarted
> .../pdb_run.py(7)<module>()
-> import sys

(Pdb)


runを使用してプログラムを再起動できます 。 実行引数はshlexを使用して解析され、コマンドラインからであるかのようにプログラムに渡されるため、異なるパラメーターでプログラムを再起動できます。

(Pdb) run abc "this is a long value"
Restarting pdb_run.py with arguments:
abc this is a long value
> .../pdb_run.py(7)<module>()
-> import sys

(Pdb) continue
Command line args: ['pdb_run.py', 'a', 'b', 'c', 'this is a long value']
The program finished and will be restarted
> .../pdb_run.py(7)<module>()
-> import sys

(Pdb)


runは、プログラムを再起動するために他のどこでも使用できます。

$ python -m pdb pdb_run.py
> .../pdb_run.py(7)<module>()
-> import sys
(Pdb) break 10
Breakpoint 1 at .../pdb_run.py:10

(Pdb) continue
> .../pdb_run.py(10)f()
-> print 'Command line args:', sys.argv

(Pdb) run one two three
Restarting pdb_run.py with arguments:
one two three
> .../pdb_run.py(7)<module>()
-> import sys

(Pdb)


エイリアスを使用したデバッガーのセットアップ

複雑なコマンドの再入力を回避する方法があります-エイリアスを定義します。 エイリアスの開示は、各チームの最初の言葉に適用されます。 エイリアスの本文には、デバッガーコマンドやPython式など、デバッガーインタープリターが許可するコマンドを含めることができます。 エイリアス定義では再帰が許可されているため、一部のエイリアスは他のエイリアスを引き起こす可能性があります。

$ python -m pdb pdb_function_arguments.py
> .../pdb_function_arguments.py(7)<module>()
-> import pdb
(Pdb) break 10
Breakpoint 1 at .../pdb_function_arguments.py:10

(Pdb) continue
> .../pdb_function_arguments.py(10)recursive_function()
-> if n > 0:

(Pdb) pp locals().keys()
['output', 'n']

(Pdb) alias pl pp locals().keys()

(Pdb) pl
['output', 'n']


引数なしでエイリアスを実行すると、定義されたエイリアスのリストが表示されます。 1つの引数-エイリアスの名前、その定義が表示されます。

(Pdb) alias
pl = pp locals().keys()

(Pdb) alias pl
pl = pp locals().keys()
(Pdb)


エイリアス引数には、%nを使用してアクセスできます。nは、1から始まる引数の番号です。すべての引数にアクセスするには、 %*を使用します。

$ python -m pdb pdb_function_arguments.py
> .../pdb_function_arguments.py(7)<module>()
-> import pdb
(Pdb) alias ph !help(%1)

(Pdb) ph locals
Help on built-in function locals in module __builtin__:

locals(...)
locals() -> dictionary

Update and return a dictionary containing the current scope's local variables.


unaliasを使用してエイリアス定義を削除します

(Pdb) unalias ph

(Pdb) ph locals
*** SyntaxError: invalid syntax (<stdin>, line 1)

(Pdb)


構成設定の保存

プログラムのデバッグには多くの繰り返しが必要です。 コードの実行、出力の分析、コードと入力の修正、および再起動 pdbは、デバッグプロセスに必要な繰り返し回数を減らして、デバッガーではなくコードに集中できるようにします。 デバッガーに与えられるコマンドの数を減らすために、 pdbを使用すると、構成を保存して、起動時に再び読み取ることができます。

〜/ .pdbrcファイルが最初に読み込まれ、すべてのデバッグセッションの個人設定を指定できます。 その後、特定のプロジェクトの設定を指定できるように、現在のディレクトリから./.pdbrcを読み取ります。

$ cat ~/.pdbrc
# Show python help
alias ph !help(%1)
# Overridden alias
alias redefined p 'home definition'

$ cat .pdbrc
# Breakpoints
break 10
# Overridden alias
alias redefined p 'local definition'

$ python -m pdb pdb_function_arguments.py
Breakpoint 1 at .../pdb_function_arguments.py:10
> .../pdb_function_arguments.py(7)<module>()
-> import pdb
(Pdb) alias
ph = !help(%1)
redefined = p 'local definition'

(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at .../pdb_function_arguments.py:10

(Pdb)


デバッガシェルに入力できる構成コマンドは、これらのファイルのいずれかに保存できますが、実行を制御するコマンド(続行、ジャンプなど)は保存できません。 例外が実行されます。つまり、。/。pdbrcでデバッグセッションのコマンドライン引数を設定して、後続の起動時に変更されないようにすることができます。

Source: https://habr.com/ru/post/J104086/


All Articles