Python | Web / API:print デバッグ

Python Python
スポンサーリンク

概要(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")
Python

reprで“実体”を見せる

文字列の空白や特殊文字、型の違いを取りこぼさないため、reprを使います。

def show(v):
    print("[debug] value=", repr(v), "type=", type(v).__name__)
Python

f文字列で要約し、過剰な全文出力は避ける

大きな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とデバッガへ橋渡しし、出力は消し忘れゼロの仕組みを用意する。この型を徹底すれば、初心者でも“速く、正確に、綺麗に”原因へ辿り着けます。

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