Python の @dataclass は、データを保持するクラスを簡潔に記述するためのデコレータです [1]。通常であれば自分で実装する必要がある __init__() や __repr__()、__eq__() などの定型コードを自動生成してくれるため、コード量を大幅に減らすことができます。
@dataclass デコレータの利用例
通常のクラスであれば、次のようにコンストラクタを実装する必要があります。
class Config:
def __init__(self):
self.host = "localhost"
self.port = 8080
self.timeout = 30
一方、@dataclass を利用すると、次のようにメンバー変数(ここでは「フィールド」と呼びます)を宣言するだけで同じようなクラスを作成できます。
from dataclasses import dataclass
@dataclass
class Config:
host: str = "localhost"
port: int = 8080
timeout: int = 30
@dataclass は、フィールドの宣言から __init__() を自動生成してくれるため、自分でコンストラクタを書く必要がありません。また、オブジェクトの内容を分かりやすく表示する __repr__() や、オブジェクト同士を比較する __eq__() なども自動的に用意されます。
このサンプルでは 3 つのフィールドだけなので、ありがたみが分かりにくいのですが、何十ものフィールドを扱うときには管理が楽なので、@dataclass デコレータを利用しています。
データクラス という名前から、メソッドを持たない単純なクラスを想像しがちですが、実際には通常のクラスとほぼ同じようにメソッドを追加できます。そのため、データだけでなく、そのデータに関連する処理も自然に記述できます。
今回は、@dataclass を利用する際によく悩む「他のクラスのインスタンスをどこで生成するか」について、__post_init__() を使った方法を備忘録としてまとめました。
他のインスタンスを初期化する方法
@dataclass デコレータを付けたクラスでは、__init__() が自動生成されるため、他のクラスのインスタンスを生成したい場合には __post_init__() を利用します。
from dataclasses import dataclass, field
class Processor:
def __init__(self, size: int):
self.size = size
@dataclass
class Config:
buffer_size: int = 1024
processor: Processor = field(init=False)
def __post_init__(self):
self.processor = Processor(size=self.buffer_size)
ポイント
- field(init=False) を指定すると、そのフィールドは @dataclass が生成する __init__() の引数に含まれません。
- __post_init__() は @dataclass が生成した __init__() の直後に呼び出されます。
- そのため、この例のように buffer_size の値を引数にして Processor のインスタンスを生成することができます。
このパターンを覚えておくと、@dataclass を利用しながら、通常のクラスと同じように他のオブジェクトを保持・初期化できるようになります。
参考サイト
にほんブログ村
#オープンソース


0 件のコメント:
コメントを投稿