【Python】dataclassと普通のクラスの使い分け
Python3.7から追加されたdataclassですが、普通のクラスとどう使い分けるのがベストプラクティスなのでしょうか?詳しい方いましたら、ご教授いただけないでしょうか。
3.7+では基本的にdataclassを使うで問題なさそうな気がしますがどうでしょうか。
Python3.7から追加されたdataclassですが、普通のクラスとどう使い分けるのがベストプラクティスなのでしょうか?詳しい方いましたら、ご教授いただけないでしょうか。
3.7+では基本的にdataclassを使うで問題なさそうな気がしますがどうでしょうか。
Pythonのdataclassは初めて知りましたが、kotlinなんかにもありますね。
ざっと見てみましたけど、私の考えは正反対です。
そもそも、データクラスとは何か。
データを保持するためのクラス、もっと言い換えると、データメンバのみ持つクラス、メソッドメンバを持たないクラスと考えます。(まぁ、実際のところPythonのdataclassはメソッドを持つことができますが、あくまでそれが目的ではない、という事で)
メソッドを持たないというのは、自分では何も処理しない、処理は外部に任せることになります。
これは、「クラス内部で処理を行い、外部にはそれを隠蔽して意識させないようにする」というオブジェクト指向のカプセル化の考えに反する、いわゆるアンチパターンです。
アンチパターンだからやっちゃダメ、とは言いません。
例えば、データベースから引っ張ってきたデータ、JSONなどからデシリアライズしたデータなど、データを羅列しただけの物を扱うことがあります。
このように、データクラスを使う場面と使わない場面は、きっちり分けるべき、と自分は考えます。
ワークフローのパイプラインのようなデータ中心アプローチ(DOA
)を目的としたデータ構造もように見うけられます。
具体的には、振る舞いを実行するワークフローのステージにdataclass
を入力し、結果のdataclass
を吐き出させる。
これをパイプラインでつないで最終結果を得るといった具合に。
DOA
のアプローチで使用することを目的としている対象をむりやりOOP
の土俵に上げてアンチパターンと言い切ってしまうのは乱暴に思えます。
私もそこまで詳しくなく、ベストプラクティスかどうかはわかりませんが、以下のように使い分ければいいのかなと思っています。
from dataclasses import dataclass
from datetime import date
@dataclass
class Person:
name: str
date_of_birth: date
def age(self) -> int:
pass
@dataclass
class Book:
title: str
author: Person
class LibraryApi:
def __init__(self) -> None:
self.endpoint = "http://library.com/api"
def get_books(self, author: Person) -> list[Book]:
pass
def post_review(self, book: Book, review: str) -> None:
pass
if __name__ == "__main__":
p1: Person = Person("鳥山明", date(1955, 4, 5))
b1: Book = Book("Dr.スランプ", p1)
b2: Book = Book("ドラゴンボール", p1)
p2: Person = Person("諫山創", date(1986, 8, 29))
b3: Book = Book("進撃の巨人", p2)
api: LibraryApi = LibraryApi()
api.get_books(p1)
api.post_review(b3, "いいね!")