3秒でわかる
初期化や比較の定型処理を自動生成してくれるPythonのクラス定義の書き方。データを持つだけのクラスを短く、書き間違いなく用意するために使います。
もう少し詳しく
どういうものか
dataclass は Python 3.7 で入った標準ライブラリの機能で、クラスに @dataclass を付けると、型注釈付きで並べた属性から __init__、__repr__、__eq__ を自動で作ってくれます。値を保持することが主な役割のクラスを、属性の宣言だけで用意できます。
引数で振る舞いを足すこともでき、order=True で大小比較、frozen=True で変更不可、slots=True でメモリ削減が有効になります。
なぜ必要か
同じ内容を素のクラスで書くと、属性が五つあれば __init__ に五行、__repr__ に五つの値の埋め込み、__eq__ に五項目の比較を手で書くことになります。属性を一つ足したときに、どれか一つを直し忘れる形の不具合が起きやすい場所です。自動生成に任せれば、宣言を一行足すだけで三つとも追随します。表示が読みやすくなる点も見逃せず、print したときに Item(name='珈琲', price=480) と出るのでデバッグが速くなります。
具体例
from dataclasses import dataclass, field
@dataclass(frozen=True, order=True)
class MenuItem:
price: int
name: str
tags: list[str] = field(default_factory=list)
a = MenuItem(480, "ホット珈琲")
b = MenuItem(480, "ホット珈琲")
print(a) # MenuItem(price=480, name='ホット珈琲', tags=[])
print(a == b) # True 中身が同じなら等しい
print(sorted([MenuItem(520, "アイス"), a])[0].name) # 価格で並ぶ比較の順序は宣言した順に見られるため、価格で並べたいなら price を先に置きます。
似た用語との違い
| 選択肢 | 向いている場面 |
|---|---|
| dataclass | 内部で使うデータの入れ物 |
| NamedTuple | 変更せず、タプルとしても扱いたいとき |
| Pydantic | 外部入力を実行時に検証したいとき |
dataclass の型注釈は自動では検査されません。price: int と書いた場所に文字列を渡しても、そのまま通ります。API のリクエストのように外から来る値を確かめたいなら Pydantic を選びます。
つまずきやすいところ
既定値にリストや辞書を直接書くとエラーになります。全インスタンスで同じ実体を共有してしまう事故を防ぐための仕様で、field(default_factory=list) を使います。また、既定値を持つ属性より後ろに既定値の無い属性を並べることはできません。関数の引数と同じ制約です。