Pythonの型ヒントとは、変数や関数の引数・戻り値に、「どんな型の値を想定しているか」を書いておく仕組みです。def greet(name: str) -> str: のように書きます。

大切なのは、型ヒントは実行時には検査されないということです。書いた型と違う値を渡しても、Pythonはそのまま実行します。型ヒントの効果は、エディタの補完や警告と、mypyやpyrightといった型チェッカーによる事前の検査で発揮されます。

型ヒントの書き方は、Pythonのバージョンごとに簡単になってきました。この記事では、基本から3.10以降の X | None、3.12以降の新しい書き方まで、現在の推奨に沿って解説し、型チェッカーやPydanticとの使い分けも紹介します。

基本の書き方

def greet(name: str, times: int = 1) -> str:
    return f"こんにちは、{name}" * times

count: int = 0
names: list[str] = ["山田", "佐藤"]
scores: dict[str, int] = {"山田": 80, "佐藤": 95}
point: tuple[int, int] = (10, 20)
書く場所 書き方
関数の引数 引数名: 型
関数の戻り値 -> 型
変数 変数名: 型 = 値
戻り値がない -> None

型ヒントは実行時に検査されない

greet(123)   # 引数は str のはずだが、実行するとエラーにならずに動いてしまう

実際に実行すると、123 がそのまま文字列に埋め込まれ、エラーにはなりませんでした。型の間違いを見つけるのは、型チェッカーの役割です。

バージョン別:古い書き方と新しい書き方

インターネット上の記事には、古い書き方も多く残っています。Python 3.10以降を使っているなら、右側の書き方が推奨です。

用途 古い書き方 新しい書き方 使えるバージョン
リスト・辞書 List[str]、Dict[str, int] list[str]、dict[str, int] 3.9以降
Noneかもしれない Optional[str] str | None 3.10以降
どちらかの型 Union[int, str] int | str 3.10以降
型の別名 UserId = int type UserId = int 3.12以降
ジェネリック関数 T = TypeVar("T") を定義して使う def first[T](items: list[T]) -> T: 3.12以降
def find_user(user_id: int) -> str | None:   # 見つからなければ None
    ...

type UserId = int                              # 3.12以降

def first[T](items: list[T]) -> T:             # 3.12以降:型パラメータ構文
    return items[0]

from typing import List, Optional のような import は、新しいバージョンでは不要です。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Pythonの型ヒントの書き方|3.12以降の新しい書き方まで」

よく使う型の一覧

型 意味 例
str、int、float、bool 基本の型 age: int
list[T]、dict[K, V]、set[T] コレクション tags: set[str]
tuple[int, str] 要素ごとの型が決まったタプル pair: tuple[int, str]
tuple[int, ...] 同じ型が任意の数並ぶタプル nums: tuple[int, ...]
X | None Noneかもしれない email: str | None
Any 何でもよい(型の検査をしない) 使いすぎに注意
Callable[[int, str], bool] 関数(引数の型と戻り値の型) コールバック
Literal["a", "b"] 決まった値のどれか 状態の値
TypedDict キーごとに型が決まった辞書 APIのレスポンス
Protocol 「このメソッドを持つもの」 構造的な型
Self 自分自身のクラスの型 メソッドチェーン

Callable などは、collections.abc から import するのが現在の推奨です(from collections.abc import Callable)。

実務で役立つ型

Literal:決まった値だけを許可する

from typing import Literal

type Status = Literal["draft", "published", "archived"]

def change_status(status: Status) -> None:
    ...

change_status("deleted")   # 型チェッカーがエラーにする

TypedDict:辞書のキーと型を決める

from typing import TypedDict, NotRequired

class User(TypedDict):
    id: int
    name: str
    email: NotRequired[str]   # なくてもよいキー

user: User = {"id": 1, "name": "山田"}

APIのレスポンスやJSONのように、辞書のまま扱いたいデータの構造を表すのに便利です。

Protocol:「このメソッドを持っていればよい」

from typing import Protocol

class Greeter(Protocol):
    def greet(self) -> str: ...

class Dog:                      # Greeter を継承していない
    def greet(self) -> str:
        return "ワン"

def say(g: Greeter) -> str:
    return g.greet()

say(Dog())   # greet メソッドを持っているので OK

継承していなくても、必要なメソッドを持っていれば受け入れる型です。Pythonの「アヒルのように鳴けばアヒル」という考え方(ダックタイピング)を、型で表せます。

Self:自分のクラスを返すメソッド

from dataclasses import dataclass
from typing import Self

@dataclass
class Point:
    x: int
    y: int

    def moved(self, dx: int) -> Self:
        return type(self)(self.x + dx, self.y)

型チェッカーで検査する

mypy

pip install mypy
mypy app.py

次のコードを検査すると、3つの間違いを見つけてくれました。

name = find_user(1)
print(name.upper())      # None の可能性がある
greet(123)               # int を str の引数に渡している
change_status("deleted") # 許可されていない値
app.py:40: error: Item "None" of "str | None" has no attribute "upper"  [union-attr]
app.py:41: error: Argument 1 to "greet" has incompatible type "int"; expected "str"  [arg-type]
app.py:42: error: Argument 1 to "change_status" has incompatible type "Literal['deleted']"; ...

特に1つ目の「Noneかもしれない値に、そのままメソッドを呼んでいる」は、実行時に AttributeError になる典型的な不具合で、型ヒントの効果が最も大きい場面です。

name = find_user(1)
if name is not None:
    print(name.upper())   # ここでは str であることが確定している

pyright・Pylance

VS CodeのPylanceは、pyrightという型チェッカーを使っています。設定で「Type Checking Mode」を basic や strict にすると、エディタ上で型の間違いに波線が表示されます。

ツール 特徴
mypy 最も歴史があり、情報が多い。CIでの検査によく使われる
pyright(Pylance) 高速で、VS Codeと統合されている

CIで検査する

チームで開発する場合は、プルリクエストのたびにmypyやpyrightを実行すると、型の間違いがmainに入るのを防げます。既存のプロジェクトに導入する場合は、まず緩い設定から始め、新しく書くコードから型を付けていくのが現実的です。

実行時に検証したいならPydantic

型ヒントは実行時に検査されないため、外から入ってくるデータ(APIのリクエスト、JSON、設定ファイル)の検証には使えません。この用途には、型ヒントを使って実行時に検証するライブラリのPydanticが便利です。

from pydantic import BaseModel

class User(BaseModel):
    id: int
    name: str

User(id="1", name="山田")     # id=1 name='山田'("1" を int に変換)
User(id="abc", name="山田")   # ValidationError: Input should be a valid integer
型ヒント+型チェッカー Pydantic
検査のタイミング 実行前(開発中・CI) 実行時
検査の対象 自分たちが書いたコード 外から入ってくるデータ
型の変換 しない する("1" → 1 など)

コードの中の整合性は型チェッカー、外から来るデータはPydantic、と使い分けます。FastAPIは、Pydanticを使ってリクエストを自動で検証します。

型ヒントを書くメリット

  • エディタの補完が効き、メソッド名や引数を覚えていなくても書ける
  • Noneの扱い忘れや、型の取り違えを、実行前に見つけられる
  • 関数の使い方が型から読み取れるため、ドキュメントの代わりになる
  • 変更の影響範囲を、型チェッカーが教えてくれる
  • AIのコーディング支援の精度が上がる。型が書かれていると、AIは引数や戻り値を正しく推測しやすい

よくある質問

Q. すべての変数に型ヒントを書くべきですか? A. 関数の引数と戻り値に書けば、多くの変数は型チェッカーが自動で推論します。count = 0 のように明らかなものには不要です。空のリスト items: list[str] = [] のように、推論できないものには書きます。

Q. 古いバージョンのPythonで新しい書き方を使えますか? A. ファイルの先頭に from __future__ import annotations を書くと、3.7〜3.9でも関数の注釈の中では str | None などの書き方を使えます。ただし type 文や型パラメータ構文は、3.12以降でないと使えません。

Q. Any を使ってもいいですか? A. Any を使うと、その部分の型の検査が行われなくなります。外部のライブラリなど型が不明な部分に限定し、使う場合は object や具体的な型で代えられないかを先に検討します。

Q. 型ヒントを書くと、処理が遅くなりますか? A. 実行速度にはほとんど影響しません。型ヒントは、実行時には関数の注釈として保存されるだけです。

まとめ

  • 型ヒントは、想定する型を書いておく仕組み。実行時には検査されない
  • 3.10以降は str | None、3.9以降は list[str]。Optional・List の import は不要
  • 3.12以降は type 文と def f[T] の型パラメータ構文が使える
  • Literal・TypedDict・Protocol・Self で、意図をより正確に表せる
  • mypy・pyright で実行前に検査。特にNoneの扱い忘れを防げる
  • 外から来るデータの検証には Pydantic

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Pythonの型ヒントの書き方|3.12以降の新しい書き方まで」

株式会社RJCでは、AIを活用した開発でも、型のように「意図をコードで伝える」工夫を大切にしています。こうした知識を仲間と共有しながら、一緒に成長を楽しんでいます。

株式会社RJC ― SI事業・SES事業・AI駆動開発。未経験からエンジニアに育てるのが得意な会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?