Python dataclass(frozen=True)で不変データオブジェクトを作成する
問題
設定値やAPIレスポンスデータを保持するオブジェクトを作成したものの、コードのどこかで誤って値が変更されると、デバッグが非常に困難になります。辞書型ではタイプヒントが効かず、通常のクラスで不変にするにはボイラープレートが必要です。
解決方法
dataclass(frozen=True)を使えば、1行で解決できます。
from dataclasses import dataclass
@dataclass(frozen=True)
class DatabaseConfig:
host: str
port: int
name: str
max_connections: int = 10
config = DatabaseConfig(host="localhost", port=5432, name="myapp")
config.port = 3306 # FrozenInstanceError!
__post_init__で生成時のバリデーションも可能です。
@dataclass(frozen=True)
class PriceRange:
min_price: float
max_price: float
def __post_init__(self):
if self.min_price < 0:
raise ValueError("min_priceは0以上である必要があります")
if self.min_price > self.max_price:
raise ValueError("min_priceがmax_priceを超えることはできません")
frozen dataclassはハッシュ可能なので、辞書のキーやsetの要素としても使えます。
@dataclass(frozen=True)
class Coordinate:
x: float
y: float
visited = set()
visited.add(Coordinate(1.0, 2.0)) # setに追加可能
ポイント
@dataclass(frozen=True)で最小限のコードで不変オブジェクトを作成できます- 属性の変更を試みると
FrozenInstanceErrorが発生します __post_init__で生成時のバリデーションが可能です- frozen dataclassはハッシュ可能なので、dictのキーやsetの要素として使用できます