Pydantic(パイダンティック)は、Pythonの型ヒントを書くだけで、入力データの検証と型変換をまとめて行うライブラリです。BaseModel を継承したクラスに id: int と書けば、文字列の "42" は整数の42に変換され、"abc" はどのフィールドがなぜ不正かを示す ValidationError になります。本記事のコードは Pydantic 2.13.5(2026年8月28日公開、2026年9月28日時点の最新安定版)と Python 3.13 で実行して確認し、出力は必要な部分を抜粋して載せています。
まとめ:Pydanticの要点
- 型ヒントを検証ルールとして使うデータ検証ライブラリ。読み方は「パイダンティック」
- 最新安定版は2.13.5。V2から検証の中核(pydantic-core)がRust製になった
- 基本は
BaseModelを継承し、制約はField()、独自ルールはfield_validatorとmodel_validatorで書く - JSONの読み込みは
model_validate_json()、書き出しはmodel_dump_json()。V1のparse_obj()・.dict()・.json()は非推奨 - 既定では “42”→42 のような変換をするが、V2は 4.9→4 の切り捨てや 123→”123″ の変換をしない
以下、読み方と位置付け、最小のコード、自動変換の範囲、バリデーター、JSONとの変換、使いどころの順に説明します。
Pydanticの位置付けと読み方
名前の由来と読み方
公式ドキュメントは、Pydanticという名前を「Py」と「pedantic」のかばん語(2語を縮めてつないだ語)だと説明しています。pedanticは「細かいことにうるさい、杓子定規な」という意味の英単語で、データの型に細かく口を出すライブラリの性格をそのまま表しています。
日本語では「パイダンティック」と読み、表記するのが一般的です。公式が日本語の読みを定めているわけではありませんが、pedanticの英語の発音(ペダンティック)に、Pythonの「パイ」を重ねた読み方です。
最新版2.13とRust製のpydantic-core
PyPIで配布されている最新の安定版は2.13.5(2026年8月28日)で、動作要件は Python 3.9 以上です。次期の2.14は2026年9月9日に2.14.0b2が出たベータ段階で、2.14系ではPython 3.9のサポートが打ち切られ、3.10以上が必要になります。3.9の環境を残している場合、2.13系が最後の対応版です。
2023年のV2で内部が作り直され、検証処理の中核は別パッケージの pydantic-core(Rust製)に移りました。公式ドキュメントは「Pydanticの検証ロジックの中核はRustで書かれている」と説明し、V2の発表時には「V1より約17倍速い」としていました。Web上の古い解説に「Cythonで高速化」とあるのはV1時代の話です。2.13.5には pydantic-core 2.46.5 が組み合わされます。
利用規模について、2026年9月28日に確認した公式のGet Startedページは「月5億5,000万回以上ダウンロードされ、PyPI上の約8,000パッケージが利用している」と書いており、FastAPI・Hugging Face・SQLModel・LangChain が例に挙がっています。
型ヒント・dataclassとの違い
Pythonの型ヒントそのものは実行時に何も検査しません。標準ライブラリの dataclass も同じで、次のように int と宣言したフィールドに文字列を渡しても、そのまま通ります。
from dataclasses import dataclass
@dataclass
class DP:
x: int
y: str
print(DP(x="abc", y=1))
# DP(x='abc', y=1)
mypyやPylanceのような静的型チェッカーは、コード中で型に合わない値を渡す誤りを実行前に見つけます。ただし、APIのリクエストやCSV、環境変数のように実行時に外から入ってくる値は対象外です。Pydanticはこの実行時の境界を受け持ちます。型ヒントは同じ書き方のまま、外部入力を検証・変換するのがPydanticの役割です。
| 手段 | 検査の時点 | 型変換 | JSON入出力 |
|---|---|---|---|
| 型ヒント+mypy | 実行前 | しない | なし |
| dataclass | 検査しない | しない | なし(自作) |
| TypedDict | 実行前のみ | しない | なし |
| Pydantic BaseModel | 実行時 | する(laxモード) | 組み込み |
dataclassやTypedDictのままPydanticの検証だけ使うこともできます。pydantic.dataclasses.dataclass や TypeAdapter がその入口です。名前付きタプルやdataclassの選び分けはnamedtupleとdataclass・dictの違いで扱っています。
インストールとBaseModelの基本形
本記事と同じ版を使う場合は python -m pip install "pydantic==2.13.5" でインストールします。メールアドレス型(EmailStr)を使うときは pip install "pydantic[email]" で依存を追加します。次が最小の例です。
from datetime import date
from pydantic import BaseModel, Field, ValidationError
class User(BaseModel):
id: int
name: str = Field(min_length=1, max_length=20)
email: str
signup: date
tags: list[str] = []
u = User(id="42", name="Sato", email="[email protected]", signup="2026-09-28")
print(repr(u))
# User(id=42, name='Sato', email='[email protected]', signup=datetime.date(2026, 9, 28), tags=[])
print(u.model_dump())
# {'id': 42, 'name': 'Sato', 'email': '[email protected]', 'signup': datetime.date(2026, 9, 28), 'tags': []}
文字列で渡した id は int に、signup は datetime.date に変換されています。Field() は既定値と制約をまとめて書く関数で、min_length・max_length(文字列やリストの長さ)、gt・ge・lt・le(数値の範囲)、pattern(正規表現)、alias(外部データ側のキー名)がよく使う引数です。
tags: list[str] = [] のように可変の既定値を直接書けるのも、dataclassとの違いです。Pydanticはリストなどハッシュ化できない既定値をインスタンスごとにディープコピーするため、この例ではリストが共有されません。
ValidationErrorの読み方
不正な値を渡すと、Pydanticは最初のエラーで止まらず、すべてのフィールドを検査してからまとめて報告します。
try:
User(id="abc", name="", email="x", signup="2026-13-01")
except ValidationError as e:
print(e.error_count()) # 3
print(e)
3 validation errors for User
id
Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='abc', input_type=str]
For further information visit https://errors.pydantic.dev/2.13/v/int_parsing
name
String should have at least 1 character [type=string_too_short, input_value='', input_type=str]
For further information visit https://errors.pydantic.dev/2.13/v/string_too_short
signup
Input should be a valid date or datetime, month value is outside expected range of 1-12 [type=date_from_datetime_parsing, input_value='2026-13-01', input_type=str]
For further information visit https://errors.pydantic.dev/2.13/v/date_from_datetime_parsing
各エラーは「フィールド名」「英語のメッセージ」「type= のエラー種別」の3点で読みます。email="x" はエラーになっていません。str と宣言しただけでは形式を検査しないためで、メール形式を強制するには EmailStr を使います。
プログラムで分岐するときは、メッセージ文ではなく e.errors() が返す辞書の type と loc を見ます。メッセージは版で変わることがありますが、int_parsing のような種別名は変わりにくいためです。
try:
User(id="abc", name="", email="x", signup="2026-13-01")
except ValidationError as e:
print(e.errors()[0])
# {'type': 'int_parsing', 'loc': ('id',), 'msg': 'Input should be a valid integer, unable to parse string as an integer', 'input': 'abc', 'url': 'https://errors.pydantic.dev/2.13/v/int_parsing'}
自動変換の範囲:laxモードの実測とV1との差
Pydanticは既定で「laxモード」で動き、型ごとの変換規則に従って入力を宣言した型に変換します。ただし、変換で情報が失われる場合もあります。どこまでが変換され、どこからがエラーかは、ドキュメントを読むより表で見たほうが早いので、TypeAdapter(型).validate_python(値) で1件ずつ確かめました。右列は strict=True を付けた場合です。
| 宣言した型 | 入力 | laxモード(既定) | strictモード |
|---|---|---|---|
| int | “42” | 42 | int_type |
| int | ” 42 “ | 42 | int_type |
| int | “1_000” | 1000 | int_type |
| int | 4.0 | 4 | int_type |
| int | 4.5 | int_from_float | int_type |
| int | True | 1 | int_type |
| float | 3 | 3.0 | 3.0 |
| bool | “yes” / “on” / “1” | True | bool_type |
| bool | 2 | bool_parsing | bool_type |
| str | 123 | string_type | string_type |
| str | b”abc” | “abc” | string_type |
| date | “2026-09-28” | date(2026, 9, 28) | date_type |
| date | “2026/09/28” | date_from_datetime_parsing | date_type |
| list[int] | (“1”, “2”) | [1, 2] | list_type |
表で英字だけのセルは、エラーになったときの種別名です。見落としやすい点が3つあります。int 型に True を渡すと1として通ること、日付文字列の「2026/09/28」はエラーになる一方、ハイフン区切りの日付以外にも条件を満たすUnix時刻やdatetimeを受け付けること、そして str 型に数値の123を渡すとエラーになることです。
最後の点はV1からの変更です。同じ環境に同梱されている pydantic.v1 で試すと、V1は123を "123" に変換し、int 型に4.9を渡すと4に切り捨てていました。V2はどちらもエラーにします。V1時代の記事のコードがV2で動かない場合、この変換規則の差が原因の一つになります。
from pydantic.v1 import BaseModel as V1Model
class V1(V1Model):
s: str
i: int
print(V1(s=123, i=4.9))
# s='123' i=4 ← V2では s も i も検証エラー
変換を止めたいフィールドには Field(strict=True) を付けます。JSONを model_validate_json() で読む場合は、strictモードでも "2026-09-28" のような文字列から date への変換は許されます(JSONに日付型が無いため)。モデル全体へのstrictの掛け方とV1からの設定の移し替えは、Pydantic v2のConfigDict設定一覧にまとめています。
field_validatorとmodel_validatorによる独自ルール
型と Field() の制約で書けないルールはバリデーターで足します。1つのフィールドだけを見るなら @field_validator、複数のフィールドを突き合わせるなら @model_validator です。
from datetime import date
from pydantic import BaseModel, field_validator, model_validator
class Reservation(BaseModel):
guest: str
check_in: date
check_out: date
@field_validator("guest")
@classmethod
def strip_guest(cls, v: str) -> str:
v = v.strip()
if not v:
raise ValueError("氏名が空です")
return v
@model_validator(mode="after")
def check_dates(self):
if self.check_out <= self.check_in:
raise ValueError("check_out は check_in より後の日付にしてください")
return self
print(Reservation(guest=" 田中 ", check_in="2026-10-01", check_out="2026-10-03"))
# guest='田中' check_in=datetime.date(2026, 10, 1) check_out=datetime.date(2026, 10, 3)
バリデーターは ValueError を送出すれば検証エラーとして扱われます。上のfield_validatorは加工後のフィールド値を返し、mode=”after”のmodel_validatorは検証後のモデル自身を返します。上の例では前後の空白を落とした「田中」が保存されています。日付を逆にすると、Value error, check_out は check_in より後の日付にしてください [type=value_error, ...] という1件のエラーになります。
mode="after" は型変換が済んだ後に動くという意味で、self.check_in はすでに date 型です。変換前の生の値に手を入れたいときは mode="before" を使います。V1の @validator と @root_validator はV2では非推奨で、置き換え先が上の2つです。@root_validator は既定のまま(pre=False)書くとクラス定義の時点で PydanticUserError になり、skip_on_failure=True を付けないと動きません。
同じルールを複数のモデルで使うなら、デコレーターより Annotated で型に付けるほうが再利用しやすくなります。
from typing import Annotated
from pydantic import AfterValidator, TypeAdapter
def even(v: int) -> int:
if v % 2:
raise ValueError("偶数ではありません")
return v
EvenInt = Annotated[int, AfterValidator(even)]
print(TypeAdapter(list[EvenInt]).validate_json("[2, 4, 6]")) # [2, 4, 6]
# "[2, 3]" を渡すと loc=(1,) の位置で「偶数ではありません」
JSON・辞書との相互変換とJSON Schema
V2で名前が変わったメソッドの対応です。V1の書き方は2.13でも動きますが、呼ぶたびに非推奨の警告が出ます。
| 処理 | V2(現行) | V1(非推奨) |
|---|---|---|
| 辞書から生成 | Model.model_validate(d) | Model.parse_obj(d) |
| JSON文字列から生成 | Model.model_validate_json(s) | Model.parse_raw(s) |
| 辞書へ出力 | m.model_dump() | m.dict() |
| JSON文字列へ出力 | m.model_dump_json() | m.json() |
| JSON Schema出力 | Model.model_json_schema() | Model.schema() |
| 検証なしで生成 | Model.model_construct() | Model.construct() |
JSONを読むときは json.loads() で辞書にしてから model_validate() に渡すより、文字列のまま model_validate_json() に渡します。公式のパフォーマンスガイドも通常はこの書き方を勧めており、JSONの解析とモデルの検証がpydantic-coreの中で済みます。ただし、mode="before" や mode="wrap" のバリデーターを使う場合は、先に json.loads() で辞書にするほうが速くなることがあると同じガイドに書かれています。ネストしたモデルの場合、エラーの loc は深さまで示します。
from pydantic import BaseModel, Field
class Item(BaseModel):
sku: str
qty: int = Field(gt=0)
class Order(BaseModel):
order_id: int
items: list[Item]
Order.model_validate_json('{"order_id": 1, "items": [{"sku": "A-1", "qty": 2}, {"sku": "B-2", "qty": 0}]}')
# ValidationError: loc=('items', 1, 'qty') type=greater_than
2件目の明細の qty が0だと、('items', 1, 'qty') という経路で場所が返ります。APIのエラーレスポンスにそのまま載せられる形です。
model_dump_json() は date を "2026-09-28" のような文字列に変換して出力します。一方、model_dump() は date オブジェクトのまま返すので、辞書を json.dumps() に渡すと失敗します。JSONにしたいなら最初から model_dump_json() か model_dump(mode="json") を使います。
モデル定義からJSON Schemaも出せます。Item.model_json_schema() の結果は次のとおりで、Field(gt=0) が exclusiveMinimum に反映されています。
{"properties": {"sku": {"title": "Sku", "type": "string"}, "qty": {"exclusiveMinimum": 0, "title": "Qty", "type": "integer"}}, "required": ["sku", "qty"], "title": "Item", "type": "object"}
Pydanticが使われる場面
FastAPIのリクエストとレスポンス
FastAPIはエンドポイントの引数に BaseModel を書くと、リクエストボディの検証、422エラーの応答、OpenAPIドキュメントの生成をすべてPydanticのモデルから行います。FastAPIは0.126.0(2025年12月20日)で単体のPydantic V1のサポートを、0.128.0(2025年12月27日)で pydantic.v1 名前空間のサポートも終了しました。現行のFastAPIでは、V2の書き方で定義したモデルしか使えません。FastAPIの仕組みと始め方はFastAPIの概要記事で解説しています。データベースのテーブル定義とPydanticモデルを1つのクラスで兼ねたい場合は、SQLModelが選択肢になります。
環境変数と設定ファイル(pydantic-settings)
V1では本体に入っていた BaseSettings は、V2から別パッケージの pydantic-settings(pip install pydantic-settings)に移りました。環境変数を型付きで読み込み、"true" をboolに、"9000" をintに変換します。
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="APP_")
debug: bool = False
port: int = 8000
# 環境変数 APP_DEBUG=true APP_PORT=9000 のとき
print(Settings())
# debug=True port=9000
LLM構造化出力でのJSON Schema生成と検証
生成AIのAPIでJSONを返させる用途でもPydanticは定番です。モデルクラスからJSON Schemaを作ってAPIに渡し、返ってきたJSONを同じクラスで検証します。OpenAIのPython SDK、LangChain、PydanticAIがこの形を採っています。仕組みと実装はLLM構造化出力の解説を参照してください。
Pydanticを使わないほうがよい場面
Pydanticは外部から来るデータの入口で使う道具で、アプリケーション内部の値の受け渡しにまで使う必要はありません。検証にはコストがかかります。この記事の実行環境(Intel Core i9-9880H・Python 3.13)で、x: int と y: str を持つモデルに同じ辞書をキーワード引数として渡し、timeit.repeat で20万回の生成を5回測定して最小値を採ったところ、1件あたり dataclass は約0.7〜0.8マイクロ秒、BaseModel は約3.0マイクロ秒でした。
1件ずつなら無視できる差ですが、すでに検証済みのデータを内部で何度も詰め替える処理や、数百万行を1行ずつモデル化するバッチでは積み上がります。次の場合はdataclassやTypedDictで十分です。
- 自分のコードの中だけで作って使う値で、外部入力を含まない
- 入口ですでにPydanticで検証したデータを、内部の関数間で受け渡すだけ
- 大量の表形式データを扱い、列単位の検証(pandasやPolarsの型指定)で足りる
逆に、APIのリクエスト、設定値、外部サービスからのレスポンス、LLMの出力のように「中身を信用できないデータ」が入ってくる境界では、Pydanticで一度検証してから内部に渡す設計が崩れにくくなります。
よくある質問
Pydanticの読み方は?
日本語では「パイダンティック」と読むのが一般的です。公式ドキュメントは名前の由来を、Python の「Py」と、英語で「細かいことにうるさい」を意味する「pedantic」を組み合わせた語だと説明しています。
PydanticのBaseModelとは?
データの形を定義するための基底クラスです。継承したクラスに型ヒント付きでフィールドを書くと、インスタンス生成時に検証と型変換が行われ、model_dump() や model_dump_json() で辞書やJSONに書き出せるようになります。
PydanticのFieldの使い方は?
name: str = Field(min_length=1, max_length=20) のように、フィールドの既定値の位置に書きます。長さ・数値範囲・正規表現などの制約、外部データのキー名(alias)、JSON Schemaに出る説明文(description)を指定できます。
Pydanticとtypingの違いは?
typing は型を「書く」ための標準モジュールで、実行時には何も検査しません。Pydanticはその型ヒントを読み取り、実行時に値を検証・変換します。typingで書いた型を、Pydanticが実行時のルールとして使う関係です。
V1のコードはV2で動きますか?
.dict() や @validator などの多くは非推奨の警告付きで動きます。ただし、str 型への数値の変換や、int 型への小数の切り捨てのような型変換の規則はV2で厳しくなっており、V1で通っていた入力がエラーになることがあります。