JSONからイミュータブルなPython Dataclassの作成
JSONデータからfrozen(イミュータブル)なPython dataclassを生成する方法を学びます。不意の変更を防ぎ、setやdictキーで使用するためのハッシュ化を有効にします。
Dataclasses
詳細な説明
frozen=Trueによるイミュータブルなdataclass
dataclassに frozen=True を設定すると、構築後のすべてのフィールドが読み取り専用になります。フィールドを変更しようとすると FrozenInstanceError が発生します。
JSONの例
{
"id": "usr_001",
"name": "Alice",
"created_at": "2024-01-15T08:00:00Z"
}
生成されるPython
from dataclasses import dataclass
@dataclass(frozen=True)
class User:
id: str
name: str
created_at: str
frozen=Trueが提供するもの
- イミュータビリティ —
user.name = "Bob"はFrozenInstanceErrorを発生させます。 - ハッシュ可能性 — frozenなdataclassは自動的に
__hash__メソッドを取得し、setやdictキーとして使用できます。 - スレッド安全性 — イミュータブルなオブジェクトはスレッド間で安全に共有できます。
frozenインスタンスの使用
user = User(id="usr_001", name="Alice", created_at="2024-01-15T08:00:00Z")
# setで使用
users = {user}
# dictキーとして使用
cache = {user: "some_value"}
# 変更を試みるとエラーが発生
user.name = "Bob" # FrozenInstanceError!
変更されたコピーの作成
frozenインスタンスは変更できないため、dataclasses.replace() を使って一部のフィールドが変更された新しいインスタンスを作成します:
from dataclasses import replace
updated = replace(user, name="Bob")
# User(id='usr_001', name='Bob', created_at='2024-01-15T08:00:00Z')
frozen=True vs slots=True
Python 3.10+では両方を組み合わせることができます:
@dataclass(frozen=True, slots=True)
class User:
id: str
name: str
slots=True は __dict__ の代わりに __slots__ を使用し、メモリ使用量を削減し属性アクセス速度を向上させます。frozen=True と組み合わせると、イミュータブルでメモリ効率の良い値オブジェクトが得られます。
frozenなDataclassを使うべき場面
- 値オブジェクト — 作成後に変更されるべきでないID、座標、金額。
- 設定 — 一度パースされ、あらゆる場所で使用され、変更されることのない設定。
- キャッシュキー — dictキーやsetメンバーにはハッシュ可能性が必要です。
- ドメインイベント — イベントは起こった事実を表すもので、イミュータブルなレコードであるべきです。
ユースケース
APIレスポンスオブジェクトをディクショナリキーとして使用するキャッシュレイヤーを構築しており、キャッシュの破損を防ぐためにハッシュ可能かつイミュータブルである必要がある場合に使用します。