環境設定 数値 文字列 正規表現 リスト タプル 集合 辞書 ループ 関数 クラス データクラス 時間 パス ファイル スクレイピング その他

Python データクラスの初期化関数(__post_init__)を使う

最終更新日 2023.02.18

Python のデータクラスは変わった初期化があります。下は name といった変数が初期化されたクラスです。

from dataclasses import dataclass


@dataclass
class User:
    id: int = 0
    name: str = ''
    password: str = ''


u = User(id=2, name='Alice', password='abc')

ここまでは問題なく、よくあるデータクラスの定義です。しかし、このクラスに __init__ を追加するとエラーになります。

初期化された変数をもつデータクラスが init をもつとき

from dataclasses import dataclass


@dataclass
class User:
    id: int = 0
    name: str = ''
    password: str = ''

    def __init__(self):
        self.image = self.name + '.jpg'


u = User(id=2, name='Alice', password='abc')
# TypeError: __init__() got an unexpected keyword argument 'id'

PyCharm ではエラー箇所がオレンジ色に塗られます。

では u の初期化を消すとどうなるでしょうか。下のコードは初期化関数を活かしていない例です。

from dataclasses import dataclass


@dataclass
class User:
    id: int = 0
    name: str = ''
    password: str = ''

    def __init__(self):
        self.image = self.name + '.jpg'


u = User()
u.name = 'Alice'

print(u.name)
# Alice

print(u.image)
# .jpg

u = User() の時点で init が動くため、name は空文字であり、image には .jpg が入ります。後から name を追加しても変わりません。初期化関数をうまく使っていない典型です。

次のコードは正しい。

from dataclasses import dataclass


@dataclass
class User:
    id: int = 0
    name: str = ''
    password: str = ''

    def __post_init__(self):
        self.image = self.name + '.jpg'


u = User(id=2, name='Alice', password='abc')
u.name = 'Alice'

print(u.name)
# Alice

print(u.image)
# Alice.jpg

今回のポイントは __post_init__ です。これは初期化された変数をもつデータクラスの初期化関数です。これは u = User(name='Alice') の時点で働くため u.image に値が入ります。