[Pythonのはじめ方] Part18: pdbによるデバッグ

Python

はじめに ✨

プログラミングをしていると、予期せぬエラーやバグに遭遇することは避けられません。そんな時、コードのどこに問題があるのかを特定する作業、すなわち「デバッグ」が必要になります。Pythonには標準で強力なデバッグツール pdb (Python Debugger) が用意されています。これを使えば、print文をたくさん挿入するよりも効率的にバグの原因を突き止めることができます!

このページでは、Python初学者の方に向けて、pdb の基本的な使い方を解説します。

pdbとは? 🤔

pdb は、Pythonプログラムのための対話型ソースコードデバッガです。Pythonの標準ライブラリに含まれているため、追加のインストールは不要ですぐに利用できます。[7, 15, 21] pdb を使うことで、以下のようなことが可能になります:

  • プログラムの実行を任意の場所で一時停止する(ブレークポイントの設定)[12, 14]
  • プログラムを1行ずつ実行する(ステップ実行)[12, 14]
  • 実行中の変数の値を確認・変更する[4, 12]
  • 関数の呼び出し履歴(スタックトレース)を確認する[12, 14]
  • ソースコードを表示する[12, 14]

コマンドライン上で動作するため、GUI環境がないサーバー上などでも利用できるのが大きな利点です。[7]

pdbの基本的な使い方 🚀

pdb を起動するには、主に2つの方法があります。

1. スクリプト内でpdbを起動する

デバッグを開始したい箇所の直前に、以下のコードを追加します。[2, 3, 7, 20]

import pdb; pdb.set_trace()

または、Python 3.7以降であれば、より簡潔な組み込み関数 breakpoint() を使うこともできます。[3, 4, 12, 20]

breakpoint()

これらのコードが実行されると、プログラムはその場で一時停止し、ターミナルに (Pdb) というプロンプトが表示され、デバッグモードに入ります。[3, 4]

例:

def add_numbers(a, b):
    result = a + b
    print(f"中間結果: {result}")
    # ここでデバッグを開始したい
    import pdb; pdb.set_trace()
    # Python 3.7+ なら breakpoint() でもOK
    # breakpoint()
    final_result = result * 2
    return final_result

x = 10
y = 5
sum_result = add_numbers(x, y)
print(f"最終結果: {sum_result}")

このスクリプトを実行すると、pdb.set_trace() (または breakpoint()) の次の行(final_result = result * 2)を実行する直前で停止し、デバッグを開始できます。[2, 20]

2. コマンドラインからpdbを起動する

スクリプトファイルを変更せずにデバッグを開始したい場合は、コマンドラインから pdb モジュールを実行します。[1, 3, 5, 11]

python -m pdb myscript.py

ここで myscript.py はデバッグしたいPythonスクリプトのファイル名です。

この方法で起動すると、スクリプトの最初の行を実行する直前でデバッグモードに入ります。[1, 3, 10] また、プログラムが例外で異常終了した場合、自動的に事後解析デバッグモードに入ることができます。[1, 3, 6]

pdbの主要コマンド一覧 ⌨️

(Pdb) プロンプトが表示されたら、以下のコマンドを入力してデバッグ操作を行います。多くのコマンドは1文字か2文字の省略形が使えます。[4, 9]

コマンド省略形説明
help [command]h利用可能なコマンドの一覧や、特定のコマンドのヘルプを表示します。[4, 8, 9]
list [first[, last]]l現在位置周辺のソースコードを表示します。引数なしだと11行表示します。[4, 8, 9, 14] (ll で関数全体を表示する機能を持つ拡張版もあります[8, 9])
nextn現在の行を実行し、次の行へ進みます。関数呼び出しがあってもその中には入りません。[4, 8, 9, 14]
steps現在の行を実行し、次の行へ進みます。関数呼び出しがあればその中に入ります。[4, 8, 9, 14]
continuec次のブレークポイントまで、またはプログラムが終了するまで実行を継続します。[3, 4, 8, 9]
returnr現在の関数が終了する(returnする)まで実行を続けます。[6, 8, 9]
quitqデバッガを終了し、プログラムの実行を中断します。[4, 8, 9, 16]
print <expression>p式(変数名など)を評価し、その値を表示します。[3, 4, 8, 9, 17]
argsa現在の関数の引数を表示します。[8, 9, 14]
break [lineno | function]b指定した行番号や関数名の最初の行にブレークポイントを設定します。引数なしで設定済みブレークポイント一覧を表示します。[4, 8, 9, 14, 17]
clear [bpnumber | filename:lineno]cl指定したブレークポイントを削除します。引数なしですべてのブレークポイントを削除します。[4, 8, 9, 14]
wherew / bt現在の関数呼び出しスタック(スタックトレース)を表示します。[8, 9, 14, 17]
up [count]uスタックフレームを一つ上(呼び出し元)に移動します。[8, 14, 17]
down [count]dスタックフレームを一つ下(呼び出し先)に移動します。[8, 14, 17]
! <statement>!デバッグ中のコンテキストでPythonの文を実行します。変数に値を代入したり、関数を呼び出したりできます。[4] (コマンドとして認識されない入力もPython文として実行されます[4])

空行を入力すると、直前のコマンドが繰り返されます(ただし、list の場合は次の11行を表示します)。[4]

実践的なデバッグ例 🛠️

簡単な例を使って、pdb でのデバッグの流れを見てみましょう。

# buggy_script.py
def calculate_average(numbers):
    total = 0
    count = 0
    for num in numbers:
        # 間違い: 本来は total += num とすべき
        total = num
        count += 1

    # ゼロ除算エラーの可能性
    breakpoint() # ここでデバッグ開始
    average = total / count
    return average

data = [10, 20, 30, 40, 50]
result = calculate_average(data)
print(f"平均値: {result}")

data_empty = []
# result_empty = calculate_average(data_empty) # ここを実行するとゼロ除算エラー
# print(f"空リストの平均値: {result_empty}")

このスクリプトを python buggy_script.py で実行すると、breakpoint() の位置で停止します。

> /path/to/buggy_script.py(11)calculate_average()
-> average = total / count
(Pdb) 

ここでコマンドを使ってみましょう。

  • 変数の確認: p total と入力すると 50 と表示されます。ループ内で毎回上書きされているため、最後の値しか入っていませんね。🧐 p count5 です。
  • コードの確認: l と入力すると、現在位置周辺のコードが表示されます。
  • 次のステップへ: このまま c (continue) を入力すると、average = 50 / 5 が計算され、10.0 が出力されて正常に終了します(ただし計算結果は間違っています)。
  • ゼロ除算エラーのデバッグ: スクリプトの最後のコメントアウトを外して実行すると、空リスト data_empty を渡した際に count が 0 になり、ゼロ除算エラーが発生します。コマンドラインから python -m pdb buggy_script.py で起動し、エラー発生箇所で事後解析デバッグを行うこともできます。[1, 3, 6] (Pdb) プロンプトで p count を実行すれば、値が 0 であることを確認できます。

まとめ 🎉

pdb は Python 標準の強力なデバッガです。最初はコマンドが多くて戸惑うかもしれませんが、基本的なコマンド (n, s, c, p, b, l, q など) を覚えるだけでも、デバッグ効率は格段に向上します。[14]

print デバッグと併用したり、より高機能な ipdb [8, 22, 23] や pdb++ [23, 24] といった拡張デバッガを試してみるのも良いでしょう。

効果的なデバッグスキルを身につけて、快適な Python ライフを送りましょう! 😊

参考情報 📚

コメント

タイトルとURLをコピーしました