手を動かしながらPythonのデータクラスを理解する
「良いコード/悪いコードで学ぶ設計入門―保守しやすい 成長し続けるコードの書き方」という技術書を読んでいて、データクラスとやらをしっかり理解した方が良いと思い、手を動かしながらデータクラスについて学んでみた
(この本はJavaを前提としているが、自分はJava分からないので、ここではPythonでやってみる)
良いコード/悪いコードで学ぶ設計入門―保守しやすい 成長し続けるコードの書き方
データクラスとは
Pythonのデータクラス機能は、バージョン3.7以降追加された機能
シンプルな書き方で、__init__()メソッドと同じことをやってくれる機能
多分、
今までこんな感じで書いていたコードが、
% cat dataclass_compare_1.py class OreClass: def __init__(self, name:str, age:int = 30): self.name = name self.age = age ore = OreClass(name="Ore") print(ore.name) print(ore.age)
※ 実行結果
% python dataclass_compare_1.py Ore 30
データクラスを使うと、こんな感じでスッキリ書けるよ、
ということ
% cat dataclass_compare_2.py from dataclasses import dataclass @dataclass class OreClass: name: str age: int = 30 ore = OreClass(name="Ore") print(ore.name) print(ore.age)
※ 実行結果
% python dataclass_compare_2.py Ore 30
きっとデータクラスはこんな感じで使われるべき
公式ドキュメントを読むだけだと、データクラスの嬉しさがいまいち分からなかったので、手を動かしながら、先程のOreClassをもう少しいじってみる
以下のクラス(OreClass)は、人物の情報を持つクラス
% cat dataclass_test.py from dataclasses import dataclass from datetime import date from math import floor @dataclass(frozen=True) class OreClass: name: str gender: str birthday: date def __post_init__(self): if self.gender not in ["male", "female", "unknown"]: raise ValueError("gender is no valid") @property def age(self) -> int: age_timedelta = date.today() - self.birthday return floor(age_timedelta.days / 365 ) ore = OreClass(name="Ore", gender="male", birthday=date(1990,7,2)) print(ore) print(f"name: {ore.name}") print(f"age: {ore.age}") omae = OreClass(name="Omae", gender="female", birthday=date(1985,6,20)) print(omae) print(f"name: {omae.name}") print(f"age: {omae.age}")
データクラスは__init__を自動作成して、name、gender、birthdayのデータを格納するので、
__post_init__を使って格納されたgender情報のvalidationを行なっている
※ __post_init__は__init__の後に実行されるため
「male」「female」「unknown」以外が格納されるとエラーが上がる
また、格納されたbirthdayの情報から今の年齢を計算するメソッド、「age」を作成した
「@property」デコレータを使うことで、ageにデータとしてアクセスできるようにしている(「ore.age」のように)
データクラスで持つデータをいじるロジックは、クラス内に持ってきた方が良いそうなので、ageメソッドはOreClassの中に持ってきた
実行結果は以下の通り
% python dataclass_test.py OreClass(name='Ore', gender='male', birthday=datetime.date(1990, 7, 2)) name: Ore age: 32 OreClass(name='Omae', gender='female', birthday=datetime.date(1985, 6, 20)) name: Omae age: 37
なんとなくデータクラスを使いたくなってきた気がする。
以上。