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
に値が入ります。