Python typingモジュールとは?型ヒントの書き方を初心者向けに解説

Pythonのtypingモジュールは、変数や関数に「どんな型が入るか」を書き添えるための仕組みです。

書いても実行時の動作は変わりません。代わりに、エディタの補完とエラー検出が効くようになり、型チェッカーがバグを見つけてくれます。


型ヒントは実行時に強制されない

ここを最初に理解しておくと、以降の話が一本の線でつながります。

def greet(name: str) -> str:
    return "Hello, " + name

print(greet("佐藤"))
print(greet(123))

実行結果:

Hello, 佐藤
TypeError: can only concatenate str (not "int") to str

エラーは出ましたが、これは型ヒントが止めたのではありません。文字列と数値を+でつなごうとして失敗しただけです。

Pythonはname: strを見ても何もチェックしません。実際、書き込まれるのは辞書1つだけです。

def f(a: int, b: str = "x") -> bool: ...

print(f.__annotations__)

実行結果:

{'a': <class 'int'>, 'b': <class 'str'>, 'return': <class 'bool'>}

では何のために書くのか

価値を生むのは型チェッカーです。代表的なのがmypyで、コードを実行せずに矛盾を見つけます。

# a1.py
def greet(name: str) -> str:
    return "Hello, " + name

greet(123)
$ mypy a1.py
a1.py:4: error: Argument 1 to "greet" has incompatible type "int"; expected "str"  [arg-type]

実行する前に間違いが分かりました。テストを通さないと気づけなかったバグを、書いた瞬間に潰せます。

得られるもの 内容
早期のバグ発見 実行せずに型の矛盾を検出
エディタの補完 変数の型が分かるので候補が出る
ドキュメント代わり 引数と戻り値が読めば分かる
安全な変更 型を変えたとき影響箇所が洗い出せる

基本の書き方

age: int = 28
name: str = "佐藤"
scores: list = []

def add(a: int, b: int) -> int:
    return a + b

def show(msg: str) -> None:
    print(msg)
  • 変数は変数名: 型 = 値
  • 引数は引数名: 型
  • 戻り値は-> 型
  • 何も返さない関数は-> None

コレクションの中身まで書く

def total(nums: list[int]) -> int:
    return sum(nums)

print(total([1, 2, 3]))

実行結果:

6

listだけでは「リストである」としか伝わりません。list[int]と書けば中身が整数だと分かります。

$ mypy a9.py
a9.py:5: error: List item 0 has incompatible type "str"; expected "int"  [list-item]

この書き方はPython 3.9以降で使えます。詳しくは「Python list[int]・dict[str, int]とは?コレクションの型ヒントの書き方」で解説しています。


typingモジュールの主要な型

型 意味 解説記事
Optional[X] XかNone Optional
Union[X, Y] XかY Union
Any どんな型でも Any
Literal["r", "w"] 決まった値だけ Literal
TypedDict 辞書のキーと型を定義 TypedDict
Callable[[int], str] 関数を受け取る Callable

バージョンによって書き方が変わる

型ヒントは仕様の変化が速く、ネットの記事が古い書き方のままということがよくあります。

やりたいこと 古い書き方 新しい書き方 使える版
整数のリスト List[int] list[int] 3.9以降
文字列か数値 Union[int, str] int | str 3.10以降
Noneを許す Optional[str] str | None 3.10以降

Python 3.9で|を使うとエラーになります。

x = int | str

実行結果(Python 3.9):

TypeError: unsupported operand type(s) for |: 'type' and 'type'

対象とするPythonのバージョンで書き方を決めてください。古い環境も想定するライブラリでは、typingからimportする書き方のほうが安全です。


型チェッカーを導入する

$ pip install mypy
$ mypy your_script.py

いきなり全ファイルに適用するとエラーが大量に出て心が折れます。次の順序がおすすめです。

  1. 新しく書く関数だけ型ヒントを付ける
  2. 触ったファイルに少しずつ広げる
  3. 設定を厳しくしていく(--strictは最後)

型ヒントは全部書かなくても効果があります。書いた部分だけチェックされ、書いていない部分は素通りするだけです。


どこまで書くべきか

場面 方針
使い捨てのスクリプト 書かなくてよい
他人が使う関数 引数と戻り値は書く
ライブラリの公開API 必ず書く
チーム開発 書く(レビューが楽になる)
関数の中のローカル変数 型が明らかなら不要

「境界」に書くのが費用対効果が高いと覚えてください。関数の入口と出口が分かれば、中身は読まなくても使えます。


typingモジュールのまとめ

  • 型ヒントは実行時に強制されない。__annotations__に入るだけ
  • 価値を生むのは型チェッカー(mypy)とエディタの補完
  • コレクションは中身まで書く(list[int])
  • 3.9以降はlist[int]、3.10以降はint | str
  • 全部書かなくてよい。関数の境界から始める

あわせて読みたい

プログラミング学習に興味がある方は、まずは無料体験会へ

無料体験会・お申し込みはこちら