_masa_u
@_masa_u (Masa U.)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

【Python】dataclassと普通のクラスの使い分け

Python3.7から追加されたdataclassですが、普通のクラスとどう使い分けるのがベストプラクティスなのでしょうか?詳しい方いましたら、ご教授いただけないでしょうか。

3.7+では基本的にdataclassを使うで問題なさそうな気がしますがどうでしょうか。

0

Pythonのdataclassは初めて知りましたが、kotlinなんかにもありますね。
ざっと見てみましたけど、私の考えは正反対です。

そもそも、データクラスとは何か。
データを保持するためのクラス、もっと言い換えると、データメンバのみ持つクラス、メソッドメンバを持たないクラスと考えます。(まぁ、実際のところPythonのdataclassはメソッドを持つことができますが、あくまでそれが目的ではない、という事で)

メソッドを持たないというのは、自分では何も処理しない、処理は外部に任せることになります。
これは、「クラス内部で処理を行い、外部にはそれを隠蔽して意識させないようにする」というオブジェクト指向のカプセル化の考えに反する、いわゆるアンチパターンです。

アンチパターンだからやっちゃダメ、とは言いません。
例えば、データベースから引っ張ってきたデータ、JSONなどからデシリアライズしたデータなど、データを羅列しただけの物を扱うことがあります。

このように、データクラスを使う場面と使わない場面は、きっちり分けるべき、と自分は考えます。

1Like

ワークフローのパイプラインのようなデータ中心アプローチ(DOA)を目的としたデータ構造もように見うけられます。

具体的には、振る舞いを実行するワークフローのステージにdataclassを入力し、結果のdataclassを吐き出させる。
これをパイプラインでつないで最終結果を得るといった具合に。

DOAのアプローチで使用することを目的としている対象をむりやりOOPの土俵に上げてアンチパターンと言い切ってしまうのは乱暴に思えます。

2Like

私もそこまで詳しくなく、ベストプラクティスかどうかはわかりませんが、以下のように使い分ければいいのかなと思っています。

  • dataclass : 複数のインスタンスを生成するもの
  • 普通のclass : インスタンスを1つだけ生成するもの
example.py
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, "いいね!")
1Like

Your answer might help someone💌