Pythonの学習中に @dataclass
という便利そうなものを見つけました。
ただ、最初は「どうして勝手に __init__()
が作られるの?」「コンストラクター引数って何?」といった疑問がありました。
この記事は、自分の理解を整理するための学習記録です。
dataclassとは?
Python3.7から使える @dataclass
は、クラスに自動的に初期化処理や表示処理を追加してくれる便利な機能です。
from dataclasses import dataclass
を使って、クラス定義の上に @dataclass
を書くことで有効になります。
通常、クラスを定義するときには __init__()
を手動で書く必要があります。
class User:
def __init__(self, name, age):
self.name = name
self.age = age
user = User("Taro", 30)
print(user.name) # Taro
これが @dataclass
を使うと、次のようにすっきり書けます。
from dataclasses import dataclass
@dataclass
class User:
name: str
age: int
user = User("Taro", 30)
print(user.name) # Taro
name
や age
をクラス定義の中に書くだけで、__init__()
メソッドが自動生成され、初期化処理が自動で行われるのが大きな特徴です。
dataclassとコンストラクター引数
クラスを使ってインスタンスを作るときに渡す値(__init__()
に渡される値)を「コンストラクター引数」と呼びます。
たとえば次のようにインスタンスを作るとき、
user = User("Hanako", 25)
この "Hanako"
と 25
が、__init__()
に渡される 引数 です。
@dataclass
を使うと、自動的に下記のような __init__()
が作られているイメージです。
def __init__(self, name: str, age: int):
self.name = name
self.age = age
つまり、dataclassで定義された変数(属性)は、そのままコンストラクター引数になります。
デフォルト値と引数の順番
dataclassでも、引数にデフォルト値を設定できます。
from dataclasses import dataclass
@dataclass
class User:
name: str
age: int = 20
user1 = User("Ken")
print(user1) # User(name='Ken', age=20)
user2 = User("Ken", 35)
print(user2) # User(name='Ken', age=35)
ただし注意点として、デフォルト値がある引数の後に、デフォルト値なしの引数を書くとエラーになります。
# エラーになる例
@dataclass
class User:
name: str = "Ken"
age: int # ❌ デフォルト値がない引数が後ろに来ている
# 正しい例
@dataclass
class User:
name: str
age: int = 20 # ✅ デフォルト値がある引数が後ろ
このように、dataclassの初期化も通常の関数定義と同じく、「位置引数 → キーワード引数」の順に並べる必要があるということを覚えておくと安心です。
field()を使ってコンストラクター引数を制御する
もっと細かく初期化の挙動を変えたいときには、field()
を使います。
たとえば init=False
を指定すれば、__init__()
の引数に含めないようにできます。
from dataclasses import dataclass, field
@dataclass
class User:
name: str
age: int = 20
id: int = field(init=False)
user = User("Miki")
user.id = 1001 # 後から代入する
print(user) # User(name='Miki', age=20, id=1001)
このように field(init=False)
を使うことで、「後からセットしたい値」「計算で自動設定される値」などに対応できます。
まとめ
- dataclassを使うと、
__init__()
などを自動で作ってくれる - dataclassの属性はそのままコンストラクター引数になる
- デフォルト値がある引数は、必ず後ろに書く必要がある
-
field(init=False)
を使うと、その属性は__init__()
に含まれない
次回は、asdict()
を使ってdataclassを辞書に変換したり、JSONに変換する方法についてまとめる予定です。