0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

#0229(2025/08/30)mypy導入ガイド

Posted at

明日から使えるmypy導入ガイド

mypyとは、Pythonに型の“安全柵”を設け、バグの芽を実行前に摘み取る静的型チェッカーである。

この記事で得られること

  • 明日から迷わずmypyを導入・運用するための最短ルート。
  • チームでの合意形成と段階的な厳格化のコツ。
  • 既存コードに痛み少なく型を足していく実践テクニック。

なぜ今mypyか(メリット)

mypyは「型注釈(type hints)」を静的に検査し、型不一致や未定義アクセスなどを実行前に指摘する。これによりレビュー負荷やデバッグ時間が減り、変更の可視性も上がる。中級者にとっては「壊さない自信」をコードベースに埋め込む装置だ。

効果の具体例

  • リファクタ時に関数シグネチャ変更の波及漏れを早期検出。
  • 動的分岐の取り違い(OptionalUnionの未ハンドリング)を警告。
  • IDE補完の精度が上がり、読みやすさ・保守性が向上。

他ツールとの比較
下表は「Python向け型チェッカー」の横比較。用途が同じ層のものは表で並べて判断する。

ツール 特徴 強み 弱み 向き
mypy 事実上の標準的存在、豊富な設定 生態系が充実、型整合性に厳密 学習コストや警告の多さ サーバ・バッチ、長寿命コード
Pyright 高速、VS Code親和 インクリメンタルが速い 設定差異に注意 クライアント/ツール併用
pytype Google製 推論が強め セットアップが大変 社内標準がある場合

導入の前提チェック

  • Python 3.8+を推奨(typingまわりが安定)。
  • 仮想環境(venv/poetry/conda)で依存を分離。
  • 型注釈は段階導入で十分。最初から「完全カバー」は目指さない。

最短導入レシピ

  1. インストール

    pip install mypy typing-extensions
    
  2. 試しにチェック

    mypy path/to/your_package
    
  3. 最小設定ファイルを置く(リポジトリ直下にmypy.ini

    [mypy]
    python_version = 3.10
    warn_return_any = True
    warn_unused_ignores = True
    no_implicit_optional = True
    disallow_untyped_defs = True
    show_error_codes = True
    pretty = True
    
  4. まずは「警告は拾うが止めない」運用(CIを--ignore-missing-importsで回し、後述の段階的厳格化へ)。

設定の王道(理解しておくと強い主要オプション)

  • disallow_untyped_defs: 型無注釈の関数定義を禁止。まずここから。
  • no_implicit_optional: 引数のデフォルトNoneを暗黙Optionalにしない。バグ温床を除去。
  • warn_return_any: Anyを返す関数に注意喚起。型の穴を塞ぐ指標になる。
  • warn_unused_ignores: 不要な# type: ignoreを検出。ノイズの掃除。
  • strict = True: 多数の厳格化フラグを一括ON。段階導入で最終到達点に。

mypy.iniテンプレ(段階導入向け)

[mypy]
python_version = 3.10
warn_return_any = True
warn_unused_ignores = True
no_implicit_optional = True
disallow_untyped_defs = True
disallow_incomplete_defs = True
check_untyped_defs = True
show_error_context = True
show_error_codes = True
pretty = True
ignore_missing_imports = True

# モジュール単位の厳格化例
[mypy-your_pkg.core.*]
disallow_untyped_defs = True
disallow_any_generics = True

[mypy-your_pkg.legacy.*]
# 旧来コードは緩めにし、徐々に締める
disallow_untyped_defs = False

段階的厳格化のロードマップ

一気にstrictへ振ると反発が起きやすい。プロダクトリスクの高い領域から締め、周辺へ波及させるのが現実的。

段階 目的 主な設定 成功判定
Lv1 まず止血 disallow_untyped_defs, no_implicit_optional 新規/変更関数に型が付く
Lv2 穴埋め warn_return_any, check_untyped_defs 重要経路のAnyが消える
Lv3 網羅性 strict(の一部を選択) 例外的ignoreだけが残る

既存コードに型を足すベストプラクティス

  • 「外周から内側へ」。API境界、DTO(データ転送オブジェクト)、公開関数から注釈する。
  • TypedDictProtocolで“構造的型”を使い、辞書やduck typingを安全化。
  • 数値・文字列の区別が曖昧ならNewTypeで意味単位を分ける。
  • 返り値が多態ならUnion/Literal/Enumで分岐を明示。
  • 長い関数は分割→それぞれに注釈。mypyは小さく確かめるほど効く。

サンプル(導入前→後)

# before
def fetch(user, limit=None):
    data = api.get(user, limit)
    return data or []

# after
from typing import Optional, Sequence, TypedDict

class Row(TypedDict):
    id: int
    name: str

def fetch(user: str, limit: Optional[int] = None) -> Sequence[Row]:
    data: Optional[list[Row]] = api.get(user, limit)
    return data or []

失敗しがちなポイントと対処

  • Anyの増殖: 一時的にAnyで塞ぐのはOKだが、# TODO(type)タグで返済計画を明文化。
  • 外部ライブラリの型: スタブがない場合はtypes-xxxパッケージやpyrightの型定義を参考に自作stubs/を置く。
  • type: ignoreの乱用: 期限と理由を書く(# type: ignore[call-arg] 2025-09-30: 互換層削除まで)。
  • ランタイムとの乖離: assert isinstance(x, Foo)などのガードを置き、静的保証と実行時保証を一致させる。

CI/CDへの組み込み

  • ステップを分ける:lint(ruff/flake8)→typecheck(mypy)→test(pytest)。
  • 失敗時は原因を短文で出すスクリプト化(ノイズを減らす)。
  • キャッシュを使いCI時間を抑制(--cache-dir)。
  • 差分チェック:修正差分だけを厳しめに通す運用も有効。
mypy your_pkg --show-column-numbers --cache-dir .mypy_cache

チーム合意のテンプレ(運用ルールを表で一望)

項目 ルール 理由
新規コード 関数定義に必ず型注釈 / from __future__ import annotations有効化 未来の負債回避
変更コード 触れた関数の返り値・引数を型で確定 リファクタ耐性
ライブラリ 型スタブが無い場合はPR時にstub追加 継続的改善
例外 ignoreはID付与+期限 放置防止
検査粒度 重要モジュールはstrict相当 品質の山を作る

よく使う補助テク

  • from __future__ import annotationsで前方参照や循環参照を簡潔化。
  • typing_extensionsで前方機能を前倒し利用。
  • dataclassの不変化(frozen=True)で“値オブジェクト”を型と一緒に堅くする。
  • Literalで設定値の取りうる集合を閉じる。
  • Finalで定数を明示し、差し替え事故を防止。

まとめ(次の一手)

  1. pip install mypyして最小mypy.iniを置く。
  2. 重要パスからdisallow_untyped_defsで締める。
  3. warn_return_anyで穴を見つけ、TypedDict/Protocol/NewTypeで埋める。
  4. CIに組み込み、差分を厳格化。
  5. 月次で厳格度を一段上げ、年内に“主要モジュールstrict”を達成。

このガイドをそのままコミットメッセージとPRテンプレに転記すれば、明日からチームの型安全が動き出す。

FAQ(現場で出る質問)

  • Q: 速度は落ちない?
    A: mypyは開発時だけ動く静的解析。実行速度には影響しない。CIでは並列化とキャッシュで待ち時間を抑えられる。
  • Q: 動的なコードはどうする?
    A: 反射的な処理はProtocolTypedDictで“構造”を表現し、境界で型を固定してから内部へ渡す。
  • Q: NumPy/Pandasは?
    A: 型定義は整備が進んでいる。まずは引数・返り値をSequenceMappingなど抽象に寄せ、内部は最小限の注釈で進める。

導入方式の比較

方式 概要 初期コスト 維持コスト メリット デメリット
リポジトリ一括 ルートで一律設定し全体を検査 ルールが単純 初期エラーが多い
モジュール段階 重要フォルダから順次strict 痛みが小さい ばらつく
フェンス方式 境界層にAdapterを置き型固定 外界の揺れを遮断 設計負荷

現場の小技(差分重視の運用)

  • 変更ファイルだけmypyを実行、全体検査は夜間ジョブへ。
  • メトリクス(error count/Any count)を記録
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?