- Python
- 技術 💻
Pythonの型ヒントの書き方|3.12以降の新しい書き方まで
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期連続の黒字決算。