JSONからPython TypedDictへの変換
dict構文を変更せずに型安全なディクショナリアクセスを提供するPython TypedDictにJSONを変換する方法を学びます。total、NotRequired、ReadOnlyを解説します。
Pydantic & TypedDict
詳細な説明
JSONからTypedDictへ
TypedDict(typing から)は、dictインターフェースを変更せずにディクショナリに型アノテーションを追加できます。dataclassとは異なり、TypedDictの値はブラケット記法(d["key"])でアクセスします。
JSONの例
{
"id": 1,
"name": "Alice",
"email": "alice@example.com",
"role": "admin"
}
生成されるPython
from typing import TypedDict
class User(TypedDict):
id: int
name: str
email: str
role: str
使用方法
import json
data: User = json.loads(raw_json)
print(data["name"]) # "Alice" — 型チェッカーはこれがstrであることを認識
TypedDict vs dataclass
| 機能 | TypedDict | dataclass |
|---|---|---|
| アクセス構文 | d["key"] |
d.key |
| ランタイム型 | dict |
カスタムクラス |
json.loads() 互換 |
はい(直接) | いいえ(構築が必要) |
| インスタンスメソッド | なし | あり |
| バリデーション | なし | なし(またはPydantic) |
NotRequiredによるオプショナルキー
from typing import TypedDict, NotRequired
class User(TypedDict):
id: int
name: str
bio: NotRequired[str] # 不在の場合がある
total vs partial
デフォルトでは、すべてのキーが必須です(total=True)。total=False に設定するとすべてのキーがオプショナルになります:
class PartialUser(TypedDict, total=False):
id: int
name: str
email: str
ReadOnly(Python 3.13+)
from typing import ReadOnly
class Config(TypedDict):
version: ReadOnly[str]
debug: bool
TypedDictを選ぶべき場面
- 属性アクセスではなくdict型アクセス(
data["key"])が必要。 - 既存のdictベースコードに型安全性を追加したいが、リファクタリングはしたくない。
- データが直接
json.loads()から来ており、オーバーヘッドゼロの型チェックが必要。 - プレーンなdictを返すサードパーティAPIにアノテーションを追加したい。
ネストされたTypedDict
class Address(TypedDict):
street: str
city: str
class User(TypedDict):
name: str
address: Address
ネストされた値は実行時にはプレーンなdictのままですが、型チェッカーは形状を強制します。
ユースケース
JSONパースしたdictをあらゆる場所で渡す既存コードベースに型安全性を追加しており、すべての関数をdataclassインスタンスを受け取るようにリファクタリングせずにmypyカバレッジが欲しい場合に使用します。