概要(printデバッグは「流れと値」をその場で可視化する最短手段)
printデバッグは、疑わしい箇所にprintを挿入して「いつ、どの分岐で、どんな値になっているか」を直接出力し、原因に近づく方法です。初心者ほど効きますが、無秩序に出すとノイズになります。どこに置くか、何を出すか、どう片付けるかを“型”にすると、速くて綺麗なデバッグができます。
目的と基本方針(再現→観察→小さく修正)
再現条件を固定し、最小例へ切り詰めた上で、printで「値の変化点」「分岐の通過」「例外の直前」を観察します。出力は「タグ」「入力」「出力」「前後差分」の4点を短く明確に。修正は数行に留め、直後に同じ再現条件で再実行します。
まずどこに置くか(入口・分岐・境界・外部I/O)
関数の入口と出口に置く
入口で引数、出口で戻り値を記録すると、誤入力・誤計算を一撃で切り分けられます。
def calc_total(price, tax_rate):
print("[calc_total] IN:", price, tax_rate)
total = price * (1 + tax_rate)
print("[calc_total] OUT:", total)
return total
Python分岐やループの“通過点”に置く
どの条件が選ばれたか、どの要素で失敗するかを可視化します。
for i, x in enumerate(items):
if x is None:
print(f"[loop] i={i} x=None → skip")
continue
print(f"[loop] i={i} x={x}")
Python境界値の手前で置く
「> と >= の違い」「空文字とNone」の境目で誤判定が起きがちです。
def is_premium(score):
print(f"[is_premium] score={score} (boundary=100)")
return score >= 100
Python外部I/O(API・DB)の前後に置く
リクエストの要約と結果の要約を出すと、原因が絞れます。
import requests
print("[api] GET /users uid=123 timeout=5s")
r = requests.get("https://httpbin.org/get", timeout=5)
print("[api] status=", r.status_code)
Python観察の質を上げる書き方(タグ・repr・整形・出力先)
一貫した“タグ”を付ける
関数名や処理名を[]タグで先頭に付けて、どこからの出力かを明確にします。
print("[auth.login] start user=taro")
Pythonreprで“実体”を見せる
文字列の空白や特殊文字、型の違いを取りこぼさないため、reprを使います。
def show(v):
print("[debug] value=", repr(v), "type=", type(v).__name__)
Pythonf文字列で要約し、過剰な全文出力は避ける
大きなJSONはサイズと主要キーだけを出すのが賢いです。
data = {"items": [1,2,3], "meta": {"page": 1}}
print(f"[resp] size={len(str(data))} keys={list(data.keys())}")
Python出力先を切り替える(標準エラーへ)
通常の結果と混ざると読みにくいので、エラー系はstderrに流します。
import sys
print("[error] unexpected state", file=sys.stderr)
Python例題で身につける(定番のバグを短く炙り出す)
例題1:型ズレで計算が壊れる
def calc_total(price, tax_rate):
print("[calc_total] IN:", repr(price), type(price).__name__, tax_rate)
return price * (1 + tax_rate)
print(calc_total("1000", 0.1)) # 文字列×float
Python出力で price が str と分かれば、入口変換を入れます。
def calc_total(price, tax_rate):
if not isinstance(price, (int, float)):
raise TypeError("priceは数値を指定してください")
return price * (1 + tax_rate)
Python例題2:境界条件の誤り
def is_premium(score):
print(f"[is_premium] score={score} boundary=100")
return score > 100
print(is_premium(100)) # False
Python出力で100が境界だと分かれば、>=に修正します。
return score >= 100
Python例題3:API失敗の不可視化
import requests
def fetch_user(uid):
print(f"[fetch_user] uid={uid}")
r = requests.get("https://httpbin.org/status/500")
print("[fetch_user] status=", r.status_code)
if r.status_code == 200:
return r.json()
return None
Python失敗理由を見える化し、タイムアウトや例外も観察します。
import requests
def fetch_user(uid):
print(f"[fetch_user] uid={uid}")
try:
r = requests.get("https://httpbin.org/get", timeout=5)
print("[fetch_user] status=", r.status_code)
r.raise_for_status()
return r.json()
except requests.RequestException as e:
print("[fetch_user] error:", e)
return None
Pythonノイズを抑えるテクニック(フラグ・コンテキスト・デコレータ)
フラグでオン/オフできるようにする
環境変数やグローバルフラグで、出力を簡単に止められます。
import os
DEBUG = os.getenv("DEBUG", "0") in {"1", "true"}
def dprint(*args, **kwargs):
if DEBUG:
print(*args, **kwargs)
dprint("[init] debug mode on")
Pythonコンテキストで“この処理だけ”詳しく出す
from contextlib import contextmanager
@contextmanager
def debug_scope(name):
print(f"[{name}] >>>")
try:
yield
finally:
print(f"[{name}] <<<")
with debug_scope("checkout"):
print("[checkout] step=auth")
print("[checkout] step=charge")
Python関数呼び出しを自動トレースする
入口/出口へ毎回書きたくないなら、デコレータで包みます。
def trace(fn):
def wrapper(*a, **kw):
print(f"[{fn.__name__}] IN a={a} kw={kw}")
out = fn(*a, **kw)
print(f"[{fn.__name__}] OUT -> {repr(out)}")
return out
return wrapper
@trace
def add(a, b): return a + b
add(3, 5)
Pythonいつprintから卒業するか(logging・デバッガへ橋渡し)
printは「その場の観察」に最強ですが、運用や例外追跡にはloggingが適します。時刻・行番号・レベル付きで記録でき、ファイル出力やローテーションも可能です。再現が難しいときはデバッガ(ブレークポイント・ステップ実行)で“止めて覗く”に切り替えましょう。目安は「出力が増えて読みにくい」「同じ箇所に何度も差し込む」になったらlogging/デバッガへ。
片付け方(消し忘れゼロの仕組み)
開発中は dprint に集約し、リリース時はDEBUGフラグで一括停止します。タグ付きで検索しやすくし、PRやCIで“[”を含む出力の有無を簡易チェックすると消し漏れが減ります。長期的には、常用観察はloggingへ移し、printは「ピンポイントの一時観察」に限定するのが安全です。
まとめ(“どこ・何・どう変わる”を短く出して、すぐ消す)
printデバッグは、疑わしい地点にタグ付きで「入力・通過・出力」を短く出して、ズレを即確認するための最短手段です。入口/出口・分岐・境界・外部I/Oに置き、reprやstderrで質を上げ、フラグやデコレータでノイズを抑える。増え始めたらloggingとデバッガへ橋渡しし、出力は消し忘れゼロの仕組みを用意する。この型を徹底すれば、初心者でも“速く、正確に、綺麗に”原因へ辿り着けます。
