# Pydantic vs dataclasses vs TypedDict vs attrs vs msgspec：Pythonデータモデリング選定ガイド（2026）

> Pythonのデータモデリング5択を公式情報に基づき公平に比較。dataclasses/TypedDictは実行時検証なし、attrsは検証オプトインで直列化なし、msgspecは速度特化、Pydanticは検証＋スキーマ＋エコシステムのバランス。実行時検証・直列化・JSON Schema・性能・エコシステムの軸と意思決定フローで、案件に最適な選択を示します。

- 公開日: 2026-06-26
- 著者: 友田 陽大
- タグ: Python, Pydantic, 型安全, データモデリング, パフォーマンス, アーキテクチャ設計
- URL: https://tomodahinata.com/blog/pydantic-vs-dataclasses-typeddict-attrs-msgspec-comparison-guide

## 要点

- 選定の第一問は「実行時に値を検証するか」。dataclassesとTypedDictは検証しない（公式明記）。境界の外部入力を扱うなら検証するライブラリが必要
- dataclasses=stdlibの構造体（検証なし）、TypedDict=辞書の静的型付け（実行時は素のdict）、用途は信頼できる内部データの整理
- attrsは検証オプトイン＋直列化は別（cattrs）、msgspecは速度特化で直列化＋検証を高速に行う（ベンダー公称5-60x）
- Pydanticは実行時検証・JSON Schema・pydantic-settings・FastAPI等の広大なエコシステムを備えた『境界の既定値』。公式も多くの場合ボトルネックにならないと述べる
- 迷ったらフローチャート：検証不要→dataclass/TypedDict、速度が律速→msgspec、検証＋スキーマ＋エコシステム→Pydantic、細粒度制御＋直列化分離→attrs+cattrs

---

## **導入：問いは「どれが最強か」ではなく「何が要るか」**

「Python のデータモデルは結局どれを使えばいい？ Pydantic？ dataclass？」——これはよく聞かれる質問ですが、問い自体が少しずれています。**5 つの選択肢は、解いている問題が違う**からです。`dataclasses` と Pydantic を「どちらが優れているか」で比べるのは、ドライバーとインパクトレンチを比べるようなものです。

本記事は、`dataclasses`・`TypedDict`・`attrs`・`msgspec`・**Pydantic** の 5 つを、**公式の一次情報に基づいて公平に**比較します。Pydantic を売り込むための記事ではありません——むしろ「ここでは Pydantic は要らない」という判断こそ、エンジニアの信頼性を示します。`marshmallow` との比較は [marshmallow vs Pydantic](/blog/marshmallow-vs-pydantic-comparison-guide) で扱っているので、本記事は **Python 標準ライブラリ＋速度特化ライブラリ**との比較に絞ります。

最初に、選定を貫く**たった一つの問い**を提示します——**「そのデータは、信頼できない外部から来るか？」**。来るなら、実行時に値を検証するライブラリが要ります。来ない（コード内部で生成・管理される信頼できるデータ）なら、検証は不要なコストです。この軸を念頭に読み進めてください。

---

## **1. 全体像：5 つを一枚の表で**

まず結論の俯瞰図です。各セルは各プロジェクトの公式情報に基づきます。

| 軸 | **Pydantic v2** | **dataclasses** | **TypedDict** | **attrs** | **msgspec** |
| --- | --- | --- | --- | --- | --- |
| 実行時検証 | ✅ 中核機能 | ❌ なし | ❌ なし（静的のみ） | △ オプトイン | ✅ デコード時 |
| 直列化（JSON等） | ✅ 内蔵 | △ `asdict`のみ（JSON非対応） | ❌（実体は dict） | ❌（別途 cattrs） | ✅ JSON/msgpack/YAML/TOML |
| JSON Schema 生成 | ✅ | ❌ | ❌ | ❌ | ✅ |
| 性能の位置づけ | 「最速級」/Rust製コア | 検証なし＝オーバーヘッドなし | 同上 | 公称なし | **速度特化**（公称最速級） |
| 設定管理 | ✅ pydantic-settings | ❌ | ❌ | ❌ | ❌ |
| 標準 / サードパーティ | サードパーティ | **標準** | **標準** | サードパーティ | サードパーティ |
| 主な用途 | API・境界・設定・LLM出力 | 内部の構造体 | 辞書の静的型付け | 柔軟なクラス生成 | 高スループット直列化 |

ポイントは**最初の 2 行**です。「実行時検証」と「直列化」の有無が、選定をほぼ決めます。以下、1 つずつ公式情報で確認します。

---

## **2. `dataclasses`：標準ライブラリの構造体（検証はしない）**

Python 標準の `@dataclass` は、`__init__` / `__repr__` / `__eq__` などを自動生成します。**依存ゼロ**で構造化レコードが書けるのが最大の利点です。

```python
from dataclasses import dataclass


@dataclass
class InventoryItem:
    name: str
    unit_price: float
    quantity_on_hand: int = 0
```

ただし、**型アノテーションは実行時に検証されません**。公式ドキュメントは明言しています——*「（2 つの例外を除き）`@dataclass` はアノテーションで指定された型を一切調べない」*。

```python
# 型は str/float/int だが、検証されないので "壊れた" インスタンスが普通に作れる
item = InventoryItem(name=123, unit_price="無料", quantity_on_hand=None)  # エラーにならない
```

`asdict` / `astuple` で dict・tuple へ変換できますが、**JSON 直列化や JSON Schema 生成はありません**。

> 💡 **`dataclasses` を選ぶとき**：データの出どころが**信頼できる内部**（自分のコードが生成する設定オブジェクト、計算の中間結果、DTO など）で、検証も直列化も要らない場合。標準ライブラリだけで完結し、依存を増やさない——KISS と YAGNI に最も忠実な選択です。

---

## **3. `TypedDict`：辞書に「静的な型」を付ける**

`TypedDict` は、辞書のキーと値に型ヒントを与えます。しかし**実行時には何も起きません**。公式の言葉どおり——*「実行時には TypedDict のインスタンスは単なる dict」*であり、*「この期待は実行時には検査されず、型チェッカーによってのみ強制される」*。

```python
from typing import TypedDict


class Point2D(TypedDict):
    x: int
    y: int
    label: str


p: Point2D = {"x": 1, "y": 2, "label": "A"}  # 実体はただの dict。mypy だけが型を見る
```

> 💡 **`TypedDict` を選ぶとき**：JSON 由来の辞書ペイロードに**静的型チェック（mypy/Pyright）だけ**を効かせたい場合。クラスを増やさず、実行時の振る舞いも変えずに、エディタ補完と静的検査を得られます。なお Pydantic は **`TypedDict` を検証対象にできる**ので、「静的には `TypedDict`、境界では Pydantic で検証」という併用も可能です（[パフォーマンス最適化ガイド](/blog/pydantic-v2-performance-optimization-guide) で触れたとおり、Pydantic 公式も「`TypedDict` はネストモデルより約 2.5 倍速い」と認めています）。

---

## **4. `pydantic.dataclasses`：dataclass 構文に検証を足す**

「dataclass の書き心地のまま、検証だけ欲しい」——その中間解が `pydantic.dataclasses` です。標準の `@dataclass` を Pydantic 版に差し替えると、**検証と型強制が効く**ようになります。

```python
from datetime import datetime
from typing import Optional
from pydantic.dataclasses import dataclass


@dataclass
class User:
    id: int
    name: str = "John Doe"
    signup_ts: Optional[datetime] = None


user = User(id="42", signup_ts="2032-06-21T12:00")
# id="42" → 42 に型強制、signup_ts は datetime にパースされる
```

公式は*「`BaseModel` を使いたくない場合、標準の dataclass で同じデータ検証が得られる」*と説明しつつ、*「Pydantic dataclass は Pydantic モデルの置き換えではない」*とも明記しています。`model_config` の一部や `BaseModel` のメソッド群（`model_dump` 等）はそのままは使えません。

> 💡 **`pydantic.dataclasses` を選ぶとき**：既存の dataclass ベースのコードに、最小の変更で検証を導入したい場合。あるいは「dataclass の構文が好きだが、外部入力の検証は欲しい」場合。新規で API 境界をがっつり作るなら、次章以降の `BaseModel` のほうが機能が揃っています。

---

## **5. `attrs`：成熟したクラスビルダー（検証はオプトイン、直列化は別）**

`attrs` は dataclass の源流ともいえる成熟ライブラリで、クラス生成を強力かつ柔軟に制御できます（`slots`・コンバータ・バリデータなど）。**検証はオプトイン**——バリデータを明示的に付けたフィールドだけが検証されます。

```python
from attrs import define, field
import attrs


@define
class Color:
    value = field(validator=attrs.validators.instance_of(int))

    @value.validator
    def _fits_byte(self, attribute, value):
        if not 0 <= value < 256:
            raise ValueError("0〜255 の範囲で指定してください")
```

重要なのは、**`attrs` は直列化ライブラリではない**こと。公式が*「attrs は本格的な直列化ライブラリではない…姉妹プロジェクトの cattrs を見てほしい」*と述べているとおり、JSON との相互変換は **cattrs** が担います（関心の分離）。JSON Schema 生成も標準ではありません。

> 💡 **`attrs` を選ぶとき**：クラス生成を細かく制御したい（スロット最適化、コンバータ、複雑な `__init__` ロジック）、かつ直列化を意図的に分離したい（cattrs と組む）場合。Pydantic より「クラスの作り方」そのものへの自由度が高い一方、検証・スキーマ・エコシステムは自分で組み立てる必要があります。

---

## **6. `msgspec`：速度に全振りした検証＋直列化**

`msgspec` は、**直列化と検証の速度に特化**したライブラリです。`msgspec.Struct` を定義すると、JSON・MessagePack・YAML・TOML の相互変換と、**デコード時の型検証**が極めて高速に行われます。

```python
import msgspec


class User(msgspec.Struct):
    name: str
    groups: set[str] = set()
    email: str | None = None


msgspec.json.encode(User("alice", groups={"admin"}))
# b'{"name":"alice","groups":["admin"],"email":null}'

msgspec.json.decode(b'{"name":"bob","groups":[123]}', type=User)
# msgspec.ValidationError: Expected `str`, got `int` - at `$.groups[0]`
```

msgspec は JSON Schema 生成（`msgspec.json.schema`）も備えます。性能について、公式は強気な数値を**自社ベンチマークとして**掲げています——*「JSON/MessagePack 実装は Python で最速級」「msgspec は orjson が単にデコードするより速くデコード＆検証する」「構造体は一般的な操作で 5〜60 倍速い」*。

> ⚠️ **数値はベンダー公称である**：これらの倍率は msgspec 自身のベンチマークによる主張であり、第三者が中立に測ったものではありません。自分のワークロードで測ってから採用してください。一方 Pydantic 公式は性能ページの冒頭で*「多くの場合 Pydantic はボトルネックにならない」*と述べています。**「速さが本当に律速になっているか」を計測で確かめる**のが先決です（[Pydantic パフォーマンス最適化ガイド](/blog/pydantic-v2-performance-optimization-guide) 参照）。

> 💡 **`msgspec` を選ぶとき**：高スループットな API・メッセージキュー・巨大 JSON の取り込みで、**直列化＋検証が実測のボトルネック**になっている場合。速度特化のサードパーティを導入できるなら強力です。

---

## **7. `Pydantic`：検証・スキーマ・エコシステムのバランス**

Pydantic は、**実行時検証・JSON Schema 生成・`pydantic-settings`・広大なエコシステム**を一つにまとめた、いわば「境界の既定値」です。中核の `pydantic-core` は Rust 製で、公式は*「Python で最速級のデータ検証ライブラリの一つ」*と位置づけます。

```python
from pydantic import BaseModel, Field


class User(BaseModel):
    id: int
    name: str = Field(min_length=1)
    email: str


User.model_validate({"id": "42", "name": "alice", "email": "a@example.com"})
# 検証＋型強制＋（必要なら）JSON Schema 生成＋直列化がワンストップ
```

Pydantic の真の強みは、機能単体よりも**エコシステム**にあります。FastAPI・SQLModel・Django Ninja・LangChain・PydanticAI が Pydantic を土台にしており、PyPI 上で約 8,000 のパッケージが Pydantic に依存しています。「検証したモデルが、そのまま API スキーマになり、設定になり、LLM の構造化出力になる」——この一気通貫が、他にはない価値です。

> 💡 **Pydantic を選ぶとき**：外部入力を扱う**境界**（HTTP API、外部 API レスポンス、設定、LLM 出力）。検証・直列化・スキーマ・設定を一貫した型で扱いたい場合。FastAPI を使うなら事実上の標準です。「迷ったら Pydantic」が成立するのは、この守備範囲の広さゆえです。

---

## **8. 意思決定フローチャート**

最後に、選定を 1 枚のフローに落とします。

1. **実行時に値を検証する必要があるか？**（データは信頼できない外部から来るか）
   - **いいえ** → 2 へ。
   - **はい** → 3 へ。
2. （検証不要）**辞書のまま静的型付けしたい？**
   - はい → **`TypedDict`**
   - いいえ（クラスが欲しい）→ **`dataclasses`**（細粒度の制御が要るなら `attrs`）
3. （検証必要）**直列化の速度が実測のボトルネックか？**
   - はい → **`msgspec`**
   - いいえ → 4 へ。
4. **JSON Schema・設定管理・FastAPI 等のエコシステムが欲しい？**
   - はい → **Pydantic**（新規 API 境界の既定）
   - dataclass 構文を保ちたいだけ → **`pydantic.dataclasses`**
   - クラス生成の自由度＋直列化分離が欲しい → **`attrs` + cattrs**

| 状況 | 推奨 |
| --- | --- |
| FastAPI で API を作る | **Pydantic**（事実上の標準） |
| 設定・シークレット管理 | **pydantic-settings**（[ガイド](/blog/pydantic-settings-configuration-management-secrets-guide)） |
| LLM の構造化出力 | **Pydantic / PydanticAI**（[ガイド](/blog/pydantic-ai-agent-framework-production-guide)） |
| 検証不要な内部 DTO | **dataclasses** |
| 辞書の静的型付け | **TypedDict** |
| 直列化が律速の高スループット | **msgspec** |
| クラス生成の細かな制御 | **attrs + cattrs** |

---

## **結論：道具は問題に合わせて選ぶ**

5 つの選択肢は競合ではなく、**解く問題のレイヤーが違う**道具です。本記事の要点を再掲します。

1. 選定の第一問は**「外部入力を検証するか」**。`dataclasses` と `TypedDict` は**検証しない**（公式明記）。
2. **`dataclasses`** は標準の構造体、**`TypedDict`** は辞書の静的型付け——いずれも信頼できる内部データ向け。
3. **`attrs`** は検証オプトイン＋直列化分離（cattrs）、**`msgspec`** は速度特化（ただし倍率はベンダー公称）。
4. **Pydantic** は検証・スキーマ・設定・エコシステムのバランスで、**境界の既定値**。
5. 迷ったら**フローチャート**——検証の要否 → 速度の律速 → エコシステムの必要性、の順で絞る。

「最強のライブラリ」を探すより、**目の前のデータがどこから来て、何を保証したいのか**を見極めることが、保守性とコスト効率の高い設計につながります。それが分かっていれば、Pydantic を選ぶときも、あえて標準の `dataclass` で済ませるときも、自信を持って説明できます。

各プロジェクトの一次情報：

- [Pydantic](https://pydantic.dev/docs/validation/latest/) ／ [pydantic.dataclasses](https://pydantic.dev/docs/validation/latest/concepts/dataclasses/)
- [dataclasses（Python 標準）](https://docs.python.org/3/library/dataclasses.html)
- [TypedDict（Python 標準）](https://docs.python.org/3/library/typing.html#typing.TypedDict)
- [attrs](https://www.attrs.org/en/stable/) ／ [msgspec](https://jcristharif.com/msgspec/)

---

### **技術選定・データモデリング設計のご相談**

筆者は、経済産業大臣賞を受賞した B2B SaaS をはじめ、複数の本番システムで「どこに何の道具を使うか」の技術選定を主導してきました。データモデリングの選定は、性能・保守性・チームの学習コスト・エコシステムを天秤にかける意思決定です。要件に対して**過不足のないライブラリ選定**と、それに基づく型安全なアーキテクチャ設計を、生成 AI を活用して高速かつ高品質に支援します。Python バックエンドの技術選定について、お気軽にご相談ください。
