yoshiislandblog.net
元営業の駆け出しアラサーSEが、休日にMACと戯れた際の殴り書きメモ。日々勉強。日々進歩。
python

手を動かしながらPythonのデータクラスを理解する

2022-09-28

良いコード/悪いコードで学ぶ設計入門―保守しやすい 成長し続けるコードの書き方」という技術書を読んでいて、データクラスとやらをしっかり理解した方が良いと思い、手を動かしながらデータクラスについて学んでみた
(この本はJavaを前提としているが、自分はJava分からないので、ここではPythonでやってみる)

良いコード/悪いコードで学ぶ設計入門―保守しやすい 成長し続けるコードの書き方

良いコード/悪いコードで学ぶ設計入門―保守しやすい 成長し続けるコードの書き方

※ この記事で使っているコードはこちらにあげています
参考:https://github.com/yoshi-island/dataclass_work

データクラスとは

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
詳しくは、公式ドキュメントをご確認くださいmm

参考:dataclasses — データクラス

きっとデータクラスはこんな感じで使われるべき

公式ドキュメントを読むだけだと、データクラスの嬉しさがいまいち分からなかったので、手を動かしながら、先程の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

なんとなくデータクラスを使いたくなってきた気がする。
以上。