---
title: "Pydanticとは？読み方・BaseModelの使い方とV1との違い【2.13対応】"
url: "https://www.issoh.co.jp/tech/details/4838/"
published: 2025-01-15
updated: 2026-09-28
categories: ["Python"]
publisher: "株式会社一創"
---

# Pydanticとは？読み方・BaseModelの使い方とV1との違い【2.13対応】

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ページ](https://pydantic.dev/docs/validation/latest/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の違い](/tech/details/3370/)で扱っています。

## インストールと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="sato@example.com", signup="2026-09-28")
print(repr(u))
# User(id=42, name='Sato', email='sato@example.com', signup=datetime.date(2026, 9, 28), tags=[])
print(u.model_dump())
# {'id': 42, 'name': 'Sato', 'email': 'sato@example.com', '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設定一覧](/tech/details/7583/)にまとめています。

## 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の概要記事](/tech/details/3859/)で解説しています。データベースのテーブル定義とPydanticモデルを1つのクラスで兼ねたい場合は、[SQLModel](/tech/details/3598/)が選択肢になります。

### 環境変数と設定ファイル（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構造化出力の解説](/tech/details/16322/)を参照してください。

## 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で通っていた入力がエラーになることがあります。

## 関連記事

- [Pydantic v2のConfigDict設定一覧｜model\_configの書き方とv1からの移行](/tech/details/7583/)
- [FastAPIとは｜最短で動かす手順とasync/defの使い分け【2026年版】](/tech/details/3859/)
- [SQLModelとは？SQLAlchemyとPydanticを統合したPython製ORMの特徴と使い方](/tech/details/3598/)
- [LLM構造化出力とは？JSON Schemaで出力形式を保証する仕組みと実装・見送り条件を解説【2026年版】](/tech/details/16322/)
- [PydanticAIとは｜型安全なPythonエージェントの作り方を実装コードで解説](/tech/details/6743/)

---

出典: [Pydanticとは？読み方・BaseModelの使い方とV1との違い【2.13対応】](<https://www.issoh.co.jp/tech/details/4838/>)（株式会社一創）
