Pythonのdataclassで引数が属性に自動反映される理由

@dataclassを付けたクラスは、Point(10, 20)と書くだけでxとyに値が入ります。self.x = xのような代入を書いた覚えがないのに、なぜ動くのでしょうか。
結論から言うと、@dataclassがクラスに書かれた属性の宣言を読み取り、__init__メソッドを自動で作っているからです。この記事では、その仕組みと、手書きの初期化コードを減らす方法を解説します。

こんな悩みを解決します

  • コンストラクタに値を渡しただけで属性に入る理由への疑問
  • 属性が増えるたびに__init__とself.xxx = xxxを書く手間
  • @dataclassの裏側で起きていることの把握

@dataclassとは何か

Python 3.7以降の標準ライブラリdataclassesが提供するデコレータです。デコレータとは、クラスや関数の直前に@名前と書いて、機能を付け足す仕組みです。
クラスに@dataclassを付けると、次のようなメソッドが自動生成されます。

  • __init__(コンストラクタ)
  • __repr__(文字列表現)
  • __eq__(比較演算子)
  • その他のメソッド(必要に応じて)

毎回同じように書くボイラープレート(定型)コードが減るため、読みやすく保守しやすいクラスになります。

なぜコンストラクタに渡した値が自動で属性にセットされるのか

次のクラスを例にします。

from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int

このクラスで

p = Point(10, 20)

とすると、p.xは10、p.yは20になります。
x: intは「属性名: 型」の宣言で、型ヒント(アノテーション)と呼ばれます。@dataclassは、クラスが定義される時点でこの宣言を上から順に読み取り、同じ名前の引数を持つ__init__を作ります。生成されるコードは、次の手書きと同じ内容です。

def __init__(self, x: int, y: int):
    self.x = x
    self.y = y

引数は宣言した順にx、yへ割り当てられます。Point(y=20, x=10)のように名前を指定して渡すこともできます。

型ヒントは実行時にチェックされない

x: intと書いても、型の検証は行われません。Point("a", "b")のように文字列を渡してもエラーにならず、そのまま属性に入ります。型の誤りを見つけたい場合は、mypyなどの静的型チェッカーを併用します。

手書きの__init__と比べて何が変わるか

手動での__init__作成の手間を省ける

従来は、次のように書く必要がありました。

class Point:
    def __init__(self, x: int, y: int):
        self.x = x
        self.y = y

属性が10個あれば、引数の宣言と代入がそれぞれ10行必要です。@dataclassなら、属性を1行ずつ宣言するだけで済みます。

コードの可読性が向上する

属性の宣言だけで初期化コードまで揃うため、クラスの定義を見れば持っているデータの一覧がそのまま分かります。

バグを減らせる

手書きではself.x = yのような代入ミスが起こりえます。自動生成なら、宣言と代入がずれる心配がありません。

__init__の後に独自の処理を足したい場合

値のチェックや派生値の計算など、初期化の直後に処理を入れたい場合は__post_init__メソッドを使います。自動生成された__init__が属性への代入を終えた直後に呼ばれます。

@dataclass
class Point:
    x: int
    y: int

    def __post_init__(self):
        print(f'Pointが作成されました: ({self.x}, {self.y})')

このPointをPoint(10, 20)で作ると、「Pointが作成されました: (10, 20)」と表示されます。__init__自体を書き直す必要はありません。

まとめ

  • @dataclassによる属性の宣言からの__init__自動生成と、渡した引数の属性への反映
  • 引数と宣言順の対応、および型ヒントが実行時にはチェックされない点
  • 初期化コードの手書き不要化による、コードの短縮とバグの削減
  • __post_init__による初期化後の処理の追加
このエントリーをはてなブックマークに追加
にほんブログ村 IT技術ブログへ

コメント

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です