Python(+ pyenv) 3.11.5
Pythonだけでなく、プログラミングをしている際に必ずする作業がデバッグです。Pythonであればprint()関数やpprintモジュールを使うことで、変数や式の値を表示できます。
ただし、この方法だと毎回実行しなくてはいけません。
そこで、今回はPythonにデフォルトで組み込まれているデバッガーpdbをご紹介します。
ブレイクポイントと呼ばれる「止めるポイント」を設置することによって、段階的なコード内探索が可能になります。
HackATAは、エンジニアを目指す方のためのプログラミング学習コーチングサービスです。 経験豊富な現役エンジニアがあなたの学習をサポートします。
✓ 質問し放題
✓ β版公開中(2025年内の特別割引)
pdbのコマンドはあまり使うことがないため、先に一覧としてまとめておきます。
| コマンド | ショートコマンド | 動作 |
|---|---|---|
| args | a | 引数を表示 |
| break | b | 行数指定でブレイクポイントを置く |
| clear | cl | ブレイクポイントの削除 |
| continue | c, cont | 実行を続行する |
| enable | - | 指定のブレイクポイントを有効化 |
| disable | - | 指定のブレイクポイントを無効化 |
| list | l | 現在行前後のソースコード表示 |
| next | n | 関数の次の行に至るかreturnされるまで実行 |
| down | d | 階層を下げる |
| up | u | 階層を上げる |
| step | s | 現在行を実行 |
| where | w | 現在の行を表示 |
| pp | - | 式の値を表示(= pretty-print) |
| restart | - | 現在デバッグ中のプログラムを再実行 |
| return | r | returnされるまで実行 |
| quit | q | デバッガの終了 |
| help | h | コマンド一覧の表示 |
| alias | - | エイリアスの作成 |
| bt | - | whereのエイリアス |
| commands | - | 指定のブレイクポイント番号にコマンドのリストを指定 |
| condition | - | 指定のブレイクポイント番号に条件式を追加 |
| debug | - | コードをステップ実行する再帰的デバッガに入る |
| display | - | 式の変更を表示 |
| exit | q | デバッガの終了 |
| ignore | - | 指定数、ブレイクポイントを通過 |
| interact | - | インタプリタを起動 |
| jump | j | 次に実行する行の指定 |
| longlist | ll | 現在の関数、またはフレームのソースコード表示 |
| p | - | 式の値を表示 |
| retval | rv | 最後にreturnされた値を表示 |
| run | - | 現在デバッグ中のプログラムを再実行 |
| source | - | 式のソースコード取得 |
| tbreak | - | 一度で破棄されるブレイクポイントを設置 |
| unalias | - | エイリアスの削除 |
| undisplay | - | 現在のフレームで指定の式を表示しない |
| until | unt | 現在行、または指定行より先になるまで実行 |
| whatis | - | 型を表示 |
pdbは、Pythonの標準ライブラリとして提供されているデバッガーです。インタラクティブなデバッグ機能を提供しています。
主な機能は以下です。
Pythonに限らず、プログラミングしているときには常にデバッグが必要となります。自身のコードが正しく機能していることを確認しながらでないと、思わぬバグを引き起こす可能性があります。
冒頭でも説明したように、単純にprint()関数でも事足ります。
任意の箇所にprint()を挟み込むことで、その箇所で期待通りの値が代入されているかを確認できます。しかしながら、print()関数はデプロイ時に放置されてしまったり、思ったとおり動かないときに再実行が必要だったりと、使い勝手が最高と言いづらい難点もあります。
これを効率的に支えてくれるのがpdbです。
pdbは標準ライブラリのため、わざわざインストールする必要がありません。
単純にbreakpoint()を使うか、pdbをimportして使います。
スクリプト内で起動したいときは以下のように書きます。
または、先頭からデバッグを開始する場合、以下のコマンドで実行できます。
このようにすることで、pdbのデバッガー画面が表示されます。簡単に実行を確認するため、ここではcontinueを意味するcを実行してみましょう。
pdbには、多くのコマンドが存在いますが、頻繁に使用するコマンドはその一部です。
ここでは基本的なコマンドを覚えて、まずはpdbでデバッグすることに慣れましょう。
list(l)pdbのlistコマンド(ショートコマンドはl)は、現在の行の周りのソースコードを表示するために使われます。開発者がデバッグ中に自分のコードが実行されているコンテキストを理解するのに役立ちます。
以下、listを利用する例です。
まずは簡単なコードを書いてみます。
開始されたデバッガーのプロンプトで、list、またはlを実行すると以下のように表示されます。
->が表示されている行が現在実行している行です。listは、現在実行している行の前後数行を表示します。
next(n)pdbのnextコマンド(ショートコマンドはn)は、現在の関数の次の行に到達するか、リターンするまで実行を続けるために使われます。
基本的にnextコマンドはコードを一行ずつステップ実行できますが、関数に入ることはありません。(stepコマンドとの違い)
nextコマンドの例は以下です。
まずはlコマンドで現在行を確認しましょう。
9行目にいることがわかります。
次に、nextかnをタイプして実行します。デバッガーはsum_value = add(x, y)の行に移動しますが、まだ実行はしません。
next、またはnをもう一度入力すると、デバッガはsum_value = add(x, y)の行を実行します。(add関数には入らず実行されるだけ)。
このように、nextコマンドを使えばadd関数内を探索することなくコードをステップ実行できます。もしnextの代わりにstepコマンドを使った場合、add関数の中に入って、一行ずつデバッグしていくことになります。
step(s)pdbのstepコマンド(ショートコマンドs)を使うと、関数やメソッドに「入り込んで」その内部実行を調査できます。この特徴はnextコマンドとは対照的です。
前の例を流用してstepコマンドを説明します。
早速デバッガープロンプトでstepコマンドを実行してみましょう。
まずはadd()関数内に入りました。再実行しましょう。
さらに実行を進めます。
このようにstepコマンドを使うことで、関数やメソッドの内部を綿密に調べることができ、コードの各部の流れや動作を確実に理解できるようになります。
continue(c)pdbのcontinueコマンド(ショートコマンドc)を使うと、次のブレイクポイントにぶつかるまでプログラムの実行を再開できます。追加のブレークポイントが設定されていなければ、プログラムは完了するまで実行されます。
先ほどのコードを少し修正してcontinueコマンドを説明します。
早速デバッガーに入ってみましょう。
まず、最初のブレイクポイントでに位置していることがわかります。
この時点でcontinueまたはcを実行すると、プログラムは次のブレイクポイントに達するまで実行されます。ここではprint文の後に2つ目のブレイクポイントを置いたので、デバッガーはそこで停止します。
ここでもう一度continueコマンドを実行すれば、残りのブレイクポイントがないため完了まで実行されます。
continueコマンドは、スクリプト内に複数のブレイクポイントがあり、その間にあるコードを1行ずつステップ実行することなく素早く移動したい場合に便利です。
break(b)pdbのbreakコマンド(ショートコマンドb)を使うと、特定の行や関数にブレイクポイントを設置できます。設置したブレイクポイントに達すると実行が一時停止され、その時点から変数の検査や式の評価、コードのステップスルーができるようになります。
stepコマンドの例は以下です。
デバッガーに入ったら、breakコマンドでブレイクポイントを設置してみましょう。
ここでcontinueまたはcを実行すると、プログラムはsubtract関数にぶつかるまで実行されます。
また、行番号でブレイクポイントを設定可能です。たとえば、16行目(差分が出力される行)にブレイクポイントを設定したい場合は次のように入力します。
breakコマンドに引数を渡さなければ、設定したブレイクポイントを一覧表示できます。
breakコマンドを使えば、一時停止する箇所を効果的にコントロールでき、特定の箇所でコードの状態や振る舞いを調べられます。
quit(q)デバッガーを終了したい場合はquit(ショートコマンドq)を入力すれば終了します。
help(h)他のコマンドを調べたいときはhelpコマンド(ショートコマンドh)を使いましょう。
引数を渡さなければ一覧表示されます。
各コマンドを調べるときは、helpコマンドに引数として渡しましょう。
先述した基本的な機能とは別に、pdbにはより高度なデバッグ機能があります。デバッグに高機能さを求めるケースは、頻繁ではありませんが、特に障害発生時の原因調査で有効です。
エンジニアになってから数年が経ち、アプリケーションだけでなくインフラやネットワークなど広範囲で世話するようになると、障害発生時の原因調査は大切なタスクとして降り掛かってきます。
そういったときでも慌てないように、プログラムを追う方法を見ていきましょう。
pdbでは、特定の条件が満たされた時のみ実行される条件付きブレークポイントを設定できます。大きなデータをループ処理していて、特定の状況下でのみ実行を一時停止させたい場合に便利です。
例えば、数値のリストを処理するループがあり、特定の条件(例えば、ある閾値より大きな数値)に遭遇して停止させたい場合を考えてみましょう。
今回の例では以下のスクリプトを使います。
上記コマンドでデバッガーに入ると、process_numbers(nums)の行で停止します。
ここで、50以上の数値が処理されたときに実行を一時停止したいとします。process_numbers関数の内部、if num > 50の行に条件付きブレイクポイントを設定しましょう。
cで実行を続行しましょう。すると、下記のようにnumが50を越えるときに停止します。
もう一度cを実行し、再開しましょう。
上記のように、以後の処理が走りますが、最後に80があるためもう1度停止します。
post_mortempost_mortem関数を使うと、例外が発生した後にその例外を調べられます。特に、予期せぬ例外が発生した際、何が問題だったのかを理解するのに便利です。
以下にpost_mortemの使用例を示します。
このスクリプトを実行してみましょう。
以下のように、例外が発生し、エラー内容と共にデバッガーが起動します。
この場合、divide_numbers関数の内部、ちょうど例外が発生した行に位置するところから開始されます。他のpdbコマンドを使って、変数の検査、式の評価、コード内のナビゲーションをしてデバッグすることとなります。
post_mortem関数は、コード中に予期せぬ例外が発生し、例外が発生した瞬間のプログラムの状態を検査したい場合に有用です。
jump(j)jumpコマンド(ショートコマンドj)を使うと、次に実行する行を設定できます。コードの特定の部分をスキップしたり、前のポイントに戻って再実行したい場合に便利です。
ただし、jumpコマンドにはいくつか注意すべき点があります。
これらの注意点を念頭に置いて、実際にjumpコマンドを使ってみましょう。
デバッガーに入って始めてください。
例えば、「関数の途中」のprint文をスキップして、「関数の終わり」の行に直接ジャンプしたいとしましょう。目的の行番号を指定してジャンプできます。
ここでcを実行すると、最後のprint実行が確認できます。
これがもし、関数外などジャンプ制限に引っかかった場合は、以下のようにエラーが出ます。
ppppコマンドは"pretty print"の略です。辞書やリストのようなデータ構造を、より読みやすく整形して表示するのに役立ちます。
例を使ってppコマンドを紹介ます。
変数dataの内容を調査したい場合は、ppコマンドを使うことできれいに表示できます。
printであるpコマンドを使った場合は以下のようになります。ppのほうが見やすいことは一目瞭然です。
ppコマンドは、大きくネストされたデータ構造を扱う場合に有用となります。
単純に変数の中身を見るにはprint関数を使えばよいのですが、構造化されたデータの場合は読みやすさの点からppの方が望ましいでしょう。
ここまで、pdbについて紹介してきましたが、詳細なデバッグをするプログラミングは比較的大規模なものとなります。
デバッグだけに頼らず、単体テストやlinterを駆使して高品質なコードを書けるようになることが大切です。
pdbは標準ライブラリということもあり、他のライブラリと統合されていることもあるので、pdbの使い方は覚えておいて損ありません。この機会にたくさん触って、手持ちスキルにしてしまいましょう。