@dataclassデコレーターは、Python 3.7で導入された、単純なデータ保持クラスを作成する際のひな形コードを短縮するためのツールの1つです。Pythonは、型注釈を使用して自動的に__init__、__repr__、__eq__その他のメソッドを生成します。
問題の歴史:
dataclassが登場する前、開発者は手動でひな形クラスを書き、コンストラクタ、比較メソッド、reprを実装し、しばしばその後、名前付きタプルやattrsなどのライブラリに移行していました。@dataclassの導入は、このプロセスを標準化し簡素化しました。
問題:
ひな形コード(ボイラープレート)、コンストラクタや比較メソッドのコードの重複は、しばしばエラーを引き起こし、大規模アプリケーションの保守を複雑にしました。
解決策:
型注釈と特殊デコレーター@dataclassを使用することで、クラス内の必要なすべてのメソッドを自動的に生成できます。
コード例:
from dataclasses import dataclass @dataclass class Point: x: int y: int p1 = Point(10, 20) p2 = Point(10, 20) print(p1 == p2) # True、__eq__が自動生成される print(p1) # Point(x=10, y=20)、__repr__が自動生成される
主な特徴:
@dataclassは継承の動作を変更しますか(継承時の特性)?
はい。dataclassクラスの継承には特別な注意が必要です:基底クラスのフィールドは子クラスのフィールドの前に来て、コンストラクタや引数の順序が競合する場合にエラーが発生する可能性があります。基底クラスと子クラスで異なるフィールドに同じ名前がある場合、最後のものが前のものをオーバーライドします。
dataclassでフィールドのデフォルトとして変更可能な値を使用できますか?
いいえ、そのようなオブジェクト(例えば、リスト)をデフォルトとして直接使用することはできません。field(default_factory=list)を使う必要があります。そうしないと、クラスのすべてのインスタンスが同じコレクションを共有します。
例:
from dataclasses import dataclass, field @dataclass class User: values: list = field(default_factory=list)
@dataclassはすべてのシナリオで高速ですか?大量データの最適なストレージに適していますか?
いいえ。dataclassはメモリの最適化に最も効果的な選択肢ではありません。数百万のオブジェクトを保存するには、__slots__やnamedtuple、特別な構造を使用する方が良いです。dataclassは管理フィールドを追加し、スロットのようにメモリを節約しません。slots=Trueをパラメーターとして渡す(Python 3.10+)か、手動でスロットを使用することができます。
@dataclass class Cart: items: list = [] # エラー! c1 = Cart() c2 = Cart() c1.items.append("a") print(c2.items) # ['a'] — すべてのCartが同じリストを共有しています
メリット:
デメリット:
from dataclasses import dataclass, field @dataclass class Cart: items: list = field(default_factory=list) c1 = Cart() c2 = Cart() c1.items.append("a") print(c2.items) # []
メリット:
デメリット:
field(default_factory=...)について知っている必要があります(これは別途学ぶ必要があります)。