型ヒントって何?まずは「コメント」だと思ってOK
Python の「型ヒント(type hints)」は、
「この変数や関数は、こういう型を想定しているよ」という情報を、コードの中に書き添える仕組みです。
ポイントは、Python 自体は動的型付けのまま、ということです。
型ヒントを書いても、Python の実行時には基本的にチェックされません。
代わりに、エディタや静的解析ツール(mypy など)がそれを読んで、
「おかしな使い方をしていないか」を教えてくれます。
つまり、型ヒントは「コンピュータと人間の両方のための、超リッチなコメント」です。
コメントと違って、ツールがちゃんと読んでくれる、というのが本質です。
いちばん基本の型ヒント:変数と関数
変数への型ヒント
まずは、変数に型ヒントを付ける一番シンプルな例です。
age: int = 20
name: str = "Taro"
height: float = 172.5
is_active: bool = True
Python右側の値を見れば型は分かりますが、
型ヒントを書くことで「この変数はこういう意味で使うつもり」という意図がはっきりします。
あとから別の人が読んだとき、
「age は整数なんだな」「name は文字列なんだな」と一瞬で分かります。
関数への型ヒント(ここが一番重要)
型ヒントの真価は、関数に付けたときに発揮されます。
def add(a: int, b: int) -> int:
return a + b
Python引数 a と b は int
戻り値も int
ということが、コードから一目で分かります。
もう少し現実的な例を見てみます。
def format_price(price: int, currency: str) -> str:
return f"{price:,} {currency}"
Pythonこの関数を見た人は、
「price は整数で、currency は文字列で、結果は文字列なんだな」とすぐ理解できます。
テストを書くときも、呼び出す側のコードを書くときも、
「何を渡して、何が返ってくるのか」が明確になります。
リストや辞書など「コレクション型」の型ヒント
リストの型ヒント
例えば、「整数のリスト」を扱う関数を考えます。
from typing import List
def total(values: List[int]) -> int:
return sum(values)
PythonList[int] は、「int の要素を持つリスト」という意味です。List[str] なら「文字列のリスト」です。
Python 3.9 以降なら、もっとシンプルにこう書けます。
def total(values: list[int]) -> int:
return sum(values)
Pythonlist[int] のように、組み込みの list にそのまま型パラメータを書けます。
辞書の型ヒント
辞書も同じように書けます。
from typing import Dict
def get_price_map() -> Dict[str, int]:
return {"apple": 100, "banana": 120}
Pythonキーが str、値が int の辞書です。
Python 3.9 以降なら、こう書けます。
def get_price_map() -> dict[str, int]:
return {"apple": 100, "banana": 120}
Pythonこれだけで、「この辞書は何をキーにして、何を値にしているのか」が明確になります。
テストを書くときも、「キーは文字列、値は整数」という前提でケースを考えられます。
Optional と Union:「来るかもしれない」「どっちか」の表現
Optional[T] で「None かもしれない」を表す
現実のコードでは、「値がないときは None」というパターンがよく出てきます。
from typing import Optional
def find_user_name(user_id: int) -> Optional[str]:
if user_id == 1:
return "Taro"
return None
PythonOptional[str] は、「str かもしれないし、None かもしれない」という意味です。
Python 3.10 以降なら、もっと短くこう書けます。
def find_user_name(user_id: int) -> str | None:
...
Pythonこの「None かもしれない」を型で表現しておくと、
呼び出す側で「None のときどうする?」をちゃんと考えるきっかけになります。
name = find_user_name(1)
if name is not None:
print(name.upper())
Python型ヒントがないと、「うっかり None に対して .upper() を呼んで落ちる」みたいなバグが起きやすくなります。
Union で「複数の型のどれか」を表す
例えば、「整数か文字列のどちらかを受け取る」関数を考えます。
from typing import Union
def to_str(value: Union[int, float, str]) -> str:
return str(value)
PythonPython 3.10 以降なら、こう書けます。
def to_str(value: int | float | str) -> str:
return str(value)
Python「この引数は、これとこれとこれのどれか」という情報が、
型ヒントとしてコードに残ります。
dataclass と型ヒント:設計とテストが一気に楽になる
dataclass で「型付きのデータ構造」を作る
型ヒントは、dataclasses.dataclass と組み合わせると、
「きれいなデータ構造」を簡単に作れます。
from dataclasses import dataclass
@dataclass
class User:
id: int
name: str
email: str
is_active: bool = True
Pythonこのクラスを見るだけで、
id は int
name は str
email は str
is_active は bool(デフォルト True)
という情報が一瞬で分かります。
テストを書くときも、
「User をどう初期化するか」が迷いません。
def test_user_default_active():
user = User(id=1, name="Taro", email="taro@example.com")
assert user.is_active is True
Python型ヒントがないと、
「id は文字列でもいいのか?」「is_active は 0/1 でもいいのか?」
といった曖昧さが残ります。
型ヒントを付けることで、
「このクラスはこういう前提で使う」という仕様が、コードとして残ります。
型ヒントとテスト・品質の関係(ここが本当に大事)
型ヒントは「テストの前提条件」を明文化してくれる
テストを書くとき、
「この関数はどんな入力を想定しているか」を理解する必要があります。
型ヒントがあると、それがコードに書いてあります。
def calc_discount(price: int, is_member: bool) -> int:
...
Pythonこの関数に対してテストを書くなら、
price は整数(負の値はどう扱う?)
is_member は bool(True/False の両方をテストしよう)
戻り値も整数(境界値は?)
という観点が自然に出てきます。
型ヒントがないと、
「price に文字列を渡しても動くのか?」
「is_member に 0/1 を渡してもいいのか?」
といった曖昧さが残り、テストの観点もブレやすくなります。
静的解析ツール(mypy など)と組み合わせると「テスト前のテスト」になる
型ヒントを書いておくと、
mypy のような静的型チェッカーが、コードを実行せずにチェックしてくれます。
例えば、こういうコードがあったとします。
def add(a: int, b: int) -> int:
return a + b
result = add("1", "2")
PythonPython としては実行時までエラーになりませんが、
mypy は「add は int を受け取るはずなのに、str を渡している」と教えてくれます。
これは、テストを書く前に「型レベルのバグ」を潰してくれるイメージです。
テストは「ロジックの正しさ」を見るものですが、
型チェックは「使い方のミス」を早期に見つけてくれます。
型ヒント+静的解析+テスト
この三つが揃うと、品質は一気に安定します。
型ヒントでハマりやすいポイントと、初心者向けの付き合い方
最初から全部に付けなくていい
いきなりプロジェクト全体に型ヒントを付けようとすると、
ほぼ確実に挫折します。
現実的には、
新しく書くコードには、最初から型ヒントを付ける
既存コードは、触るところから少しずつ型を付けていく
くらいのペースで十分です。
特に、外から呼ばれる関数(API の入り口、サービス層の関数など)から付けていくと、
効果が出やすいです。
「型が難しいからやめる」ではなく「分かるところだけでも書く」
ジェネリクス、Protocol、TypedDict など、
typing には難しそうな機能がたくさんあります。
でも、最初から全部理解する必要はありません。
int, str, bool, list[int], dict[str, int], Optional[str]
このあたりだけでも、コードの読みやすさはかなり変わります。
「分かるところだけでも型ヒントを書く」
「分からないところは、あとで直せるようにしておく」
このくらいの気持ちで始めるのがちょうどいいです。
まとめ(型ヒントは「未来の自分と他人へのラブレター」)
型ヒントを初心者目線で整理すると、こうなります。
Python の型ヒントは、「この関数・変数はこういう型を想定している」という情報をコードに埋め込む仕組みで、実行時ではなくエディタや静的解析ツールがそれを活用する。
関数やデータ構造に型ヒントを付けることで、「何を渡して何が返るのか」が明確になり、テストの観点も揃いやすくなる。
Optional や Union、list[int] や dict[str, int] など、基本的な型ヒントだけでも、設計の意図と品質がぐっと上がる。
型ヒント+静的解析(mypy など)+テストの組み合わせは、「バグの入り込む余地」を大きく減らし、未来の自分や他の開発者が安心してコードを触れる状態を作ってくれる。

