なぜ「printデバッグ」から卒業すべきなのか?
Pythonプログラミングでバグの原因を探る際、多くの人が一度は通る道、それが「printデバッグ」です。
print("ここ通った?") print(f"変数 a の値は {a} です")
このように、怪しい箇所にprint()文を大量に仕込み、ターミナルに出力される値とにらめっこする…。心当たりのある方も多いのではないでしょうか。
この方法は手軽ですが、以下のような限界や手間がつきまといます。
- 手間と時間: デバッグが終わったら、追加した
print文をすべて削除する必要があり、消し忘れが新たなバグを生むこともあります。 - 再実行の嵐: 変数の値を変えて試したい場合、コードを修正してプログラムを最初から実行し直さなければなりません。
- 情報の洪水: 大量の
print文はターミナルを埋め尽くし、本当に必要な情報を見つけるのを困難にします。
この記事では、そんな非効率なprintデバッグからあなたを解放する、Pythonのモダンで強力なデバッグツールを紹介します。
この記事が提供する解決策
breakpoint(), globals(), locals() という3つの組み込み関数を使いこなすことで、あなたのデバッグ作業は劇的に効率化されます。この記事を読めば、その具体的な活用法がわかります。
実行状態を丸裸に!globals()とlocals()でスコープを覗く
効率的なデバッグの第一歩は、プログラムの「状態」を正確に把握することです。そのために役立つのが、変数が定義されている範囲(スコープ)の中身を覗き見できる globals() と locals() です。
globals(): プログラム全体の変数を一覧表示
globals()は、プログラム全体(モジュールレベル)で利用可能な変数や関数を辞書として返します。 これを使えば、どこからでもアクセスできるグローバル変数の状態を一目で確認できます。
# global_check.py
APP_NAME = "My Awesome App"
VERSION = "2.1"
def print_version():
print(f"{APP_NAME} - version {VERSION}")
# プログラムのどこかでglobals()を呼び出す
print(globals())このコードを実行すると、APP_NAMEやVERSIONといった自分で定義した変数を含む、たくさんの情報が辞書形式で表示されます。プログラム全体で共有されている設定値などを確認したい場合に便利です。
locals(): 関数内の変数をピンポイントで確認
locals()は、現在の場所(特に、関数の中)で利用可能な変数や引数を辞書として返します。 こちらがデバッグでは主役になります。
# local_check.py
global_value = 100
def calculator(a, b):
result = a + b
print("--- calculator関数の中 ---")
print(locals())
calculator(10, 20)これを実行すると、calculator関数の中だけで有効な情報だけが表示されます。
--- calculator関数の中 ---
{'a': 10, 'b': 20, 'result': 430}関数に渡された引数 a, b や、関数内で計算された result の値が何であるかを正確に把握できます。print()文を一つ一つ書くよりも、はるかにスマートです。
コードを好きな場所で止める魔法 breakpoint() の使い方
スコープの確認方法がわかったら、次はいよいよデバッグのゲームチェンジャー、breakpoint()の登場です。
breakpoint()とは?たった一行でデバッガを起動
breakpoint()は、Python 3.7以降で利用可能になった組み込み関数で、コードの実行をその場で一時停止し、対話型のデバッガ(PDB: The Python Debugger)を起動します。
使い方は驚くほど簡単。print()を置く代わりに、処理を止めたい行にbreakpoint()と書くだけです。
def process_data(data, threshold):
processed_list = []
for item in data:
value = item * 2
# valueがどうなっているか、この時点で確認したい!
breakpoint()
if value > threshold:
processed_list.append(value)
return processed_list
my_data = [10, 25, 5, 40]
process_data(my_data, 50)このスクリプトを実行すると、ループの最初のbreakpoint()の行で実行がピタッと止まり、ターミナルに(Pdb)と表示されます。ここからが対話型デバッグの始まりです。
デバッガ(PDB)の必須コマンド p, n, c, q
(Pdb)プロンプトでは、コマンドを使ってプログラムを操作できます。まずはこれだけ覚えましょう。
| コマンド | 意味 (覚え方) | 説明 |
p <変数名> | 変数の値を表示します。 (例: p value) | |
n | next | 次の行へ処理を進めます。 |
c | continue | 次のbreakpoint()まで、または最後まで実行を続けます。 |
q | quit | デバッガを終了します。 |
Google スプレッドシートにエクスポート
p itemやp valueと入力すれば、その時点での変数の値を確認できます。print()を書いて再実行する手間はもうありません。
実践的な活用法:breakpoint()とスコープ関数を組み合わせる
breakpoint()の本当の力は、locals()と組み合わせたときに発揮されます。これが「printデバッグ卒業」の鍵です。
locals()で変数の状態を一括チェック
先ほどのbreakpoint()で停止した(Pdb)プロンプトで、コマンドとしてlocals()を実行してみてください。
> /path/to/your/script.py(8)process_data()
-> if value > threshold:
(Pdb) locals()
{'data': [10, 25, 5, 40], 'threshold': 50, 'processed_list': [], 'item': 10, 'value': 20}
Code language: JavaScript (javascript)
どうでしょうか。print()文を5つも書かなければならなかった情報が、たった一つのコマンドで全て手に入りました。引数dataやthreshold、ループ変数item、計算結果のvalueまで、そのスコープにある変数の状態が丸見えです。
複雑な処理も怖くない!バグの原因を素早く特定する流れ
この手法を使ったデバッグの基本的な流れは以下のようになります。
- 怪しい箇所の直前に
breakpoint()を置く。 - プログラムを実行し、PDBプロンプトで停止させる。
locals()を実行し、その時点での変数全体の状態をざっと眺める。- 想定と違う値になっている変数を見つけたら、
p <変数名>で詳しく確認する。 nコマンドで一行ずつ処理を進めながら、どの計算で値がおかしくなるのかを特定する。- 原因がわかったら
qでデバッガを終了し、コードを修正する。
この流れに慣れれば、print()文を書いては消し、実行し直すというサイクルから完全に抜け出すことができます。
まとめ:スマートなデバッグで開発効率を上げよう
printデバッグは手軽ですが、あなたの貴重な時間を少しずつ奪っていきます。
今回紹介したbreakpoint(), globals(), locals()を活用することで、あなたはよりスマートで効率的なデバッグ手法を手に入れることができます。
breakpoint()で実行を止め、対話的に状態を探る。locals()で現在のスコープの変数を一網打尽にする。globals()でプログラム全体の状態を確認する。
これらのツールは、一度使い方を覚えれば一生役立つスキルです。今日のコーディングから早速breakpoint()を試して、快適なデバッグライフへの第一歩を踏み出しましょう。


コメント