メインコンテンツへスキップ

🧠 推測に頼るコード(Refuse the temptation to guess)

🧭 はじめに

このページでは、Python の Zen Refuse the temptation to guess に反するアンチパターン、 「推測に頼るコード」 を扱います。

Python は柔軟で表現力が高い言語ですが、その反面 「それっぽく書けてしまう」 ことが設計ミスを隠します。 本記事では、その曖昧さがどのように事故につながるかを整理します。


🎯 ねらい

  • Python の truthy / falsy 文化が設計と衝突する瞬間を可視化する
  • 「短い条件式」と「正しい仕様」は別物であることを示す

❓ 問題の定義

推測に頼るコードとは、

  • 値の意味を条件式の雰囲気で判断し
  • 未指定・無効・有効を曖昧に混同
  • 読み手(あるいは未来の自分)が 「きっとこういう前提だろう」と推測しないと理解できない

状態を指します。

推測は人間が補完しているだけで、コードの仕様にはなっていません


🤒 よくある症状

⚖️ truthy / falsy に丸投げ

if value:
    do_something(value)
  • 0
  • ''
  • []
  • False

これらはすべて falsy。

意味の違いが条件式で潰れる


🫥 None と空値の同一視

  • None(未指定)
  • [](指定されたが空)
  • 0(有効な数値)

が同じ扱いになる。


📐 前提があるのにチェックしない

  • 型は int のはず
  • 範囲は正のはず
  • 未指定は来ないはず

「はず」をコードに書いていない

前提を書かないコードは、前提が壊れた瞬間に嘘をつき始めます


❌ 悪い例①:ページングの罠

def fetch_items(page=1):
    if page:
        offset = (page - 1) * 20
    else:
        offset = 0
    return query(offset)

何が問題か

  • page=0 が falsy
  • 結果として 意図せず 1 ページ目扱い
  • バグなのに例外も出ない

❌ 悪い例②:金額 0 円が「未入力」になる

def apply_discount(amount):
    if amount:
        return amount * 0.9
    return None
  • amount=0 → 未入力扱い
  • 無料・全額割引・返金処理で破綻

✅ 良い例①:is None を使う

def fetch_items(page=None):
    if page is None:
        page = 1

    offset = (page - 1) * 20
    return query(offset)

改善点

  • 未指定 (None) と有効値を分離
  • 条件の意図が一意に読める
  • 推測が不要

`if x is None:` は「設計意思」を明示する構文です。


✅ 良い例②:sentinel を定義する

UNSET = object()

def apply_discount(amount=UNSET):
    if amount is UNSET:
        return None
    return amount * 0.9

ポイント

  • 「未指定」を明確な状態として表現
  • falsy な正当値と衝突しない
  • API の意味が安定する

🧩 設計の要点

曖昧さは条件式でなく仕様で解決する

  • 未指定か?
  • 無効か?
  • 有効な値か?

これらは 値の雰囲気ではなく、型や契約で表す

境界は必ず明示する

  • 関数の入口で検証
  • 型ヒント・バリデーション
  • 失敗は例外か明示的な戻り値

✅ チェックリスト

  • if x:x0 / 空 / False を取り得るか
  • 未指定と有効値を 同じ表現で扱っていないか
  • 前提条件(型・範囲)が コードに書かれているか
  • 呼び出し側が「察し」を要求されていないか

🧠 まとめ

推測に頼るコードは、

  • 短く
  • それっぽく
  • 一見 Pythonic

に見えます。

しかし Python の Zen が言う Refuse the temptation to guess とは、

書き手の推測を減らせ、ではなく 読み手に推測させるな

という設計原則です。

これで前半4本が揃いました。 次章では、🧩 過剰抽象・早すぎる一般化に進めます。