【Python】dataclass の使い方

python

Python で dataclass を使う方法についていくつか紹介します。

dataclass

エンティティを定義する手段はいろいろとありますが、今回は dataclass について説明します。

dataclass は Python 標準の機能で Python 3.7 で追加されています。バージョンには注意が必要です。
dataclass: https://docs.python.org/ja/3/library/dataclasses.html

定義方法

定義方法はデコレータをつけるだけです。

import dataclasses

@dataclasses.dataclass
class SampleEntity:
    id: int = dataclasses.field(default=None)
    name: str = dataclasses.field(default=None)

dataclass を使う場合の一番わかり易いメリットとして init の定義が不要ということがあります。内部で自動生成されるため定義不要です。

上で定義した dataclass は init の定義をすることなくインスタンス生成時に値を渡せます。

SampleEntity(id=1, name="sample")

デコレータ

dataclass のデコレータにはパラメータを付与することもできます。

@dataclasses.dataclass(init=True, frozen=True)

代表的なものを簡単に紹介します。

パラメータデフォルト説明
initTrue__init__を生成するか
eqTrue比較メソッド(__eq__)を自動で生成するか
frozenFalse変更不可にするか。いわゆるイミュータブル

フィールド定義

dataclass のフィールド定義する場合には”dataclasses.field”を使います。

使わなくても定義は可能ですが、必要な場合もあるので個人的には統一して使うようにしています。

パラメータデフォルト説明
defaultMISSINGデフォルト値。Noneを指定するとインスタンス生成時パラメータ不要になる
initTrue__init__にこのフィールドを含めるか
compareTrue比較メソッドにこのフィールドを含めるか

型定義

フィールドの型を定義するにはヒントを付けます。

id: int = dataclasses.field()
name: str = dataclasses.field()

初期値

基本データ型(int, str)などには “default=X” でいいですが、list や dict の場合には default_factory を使います。


childs: list = dataclasses.field(default_factory=list)

厳密には基本データ型かどうかではないですが、基本的な使い分けの考え方としては問題ないはずです。

初期化後の処理 (post_init)

“__post_init__”メソッドを定義した場合、”__init__”後に実行されます。

初期化後に値を設定したい処理などが記載できます。

aaa: int = dataclasses.field()
bbb: int = dataclasses.field()
xxx: int = dataclasses.field(init=False)
code: str = dataclasses.field()

def __post_init__(self):
    xxx = aaa * bbb
    code = self.code.upper() if self.code else None

初期化限定変数 (InitVar)

“InitVar”でフィールドを定義すると初期化のみに使用できるフィールドとなります。

post_init で受け取ることができます。

name: str = dataclasses.field()
append: dataclasses.InitVar(str) = None

def __post_init__(self, append):
    self.name = self.name + append

dataclass の継承

dataclass を継承したクラスを作成する場合、そのクラスも dataclass にする場合は、継承したクラスにもデコレータを付ける必要があります。

@dataclasses.dataclass
class Base:
    # 定義

# NG
class extend(Base)

# OK
@dataclasses.dataclass
class extend(base):

dataclass の判定

オブジェクトが dataclass か判定するには is_dataclass を使います。

if dataclasses.is_dataclass(data):
    print("dataclass")
else:
    print("not dataclass")

dict に変換

“asdict”を使用することで簡単に dataclass を dict に変換できます。

d = dataclasses.asdict(data)

dict_factory パラメータにメソッドを渡すことで変換に介入することもできます。

# 例
def convert(data):
    ts = []
    for name, value in data:
        val = value
        if isinstance(value, FileProxyMixin):
            # ファイル(Django) の場合、スキップ
            continue
        elif isinstance(value, bytes):
            # byte の場合、文字に変換
            val = 変換処理(value)
        elif isinstance(value, TypeBase):
            # オリジナルの区分値(Enumを便利に使う記事参照)
            val = value.val
        ts.append((name, val))
    return dict(ts)

d = dataclasses.asdict(data, dict_factory=convert)

その他、データクラスはいろいろ便利に使えるので公式や記事を参照して使ってみてください。

タイトルとURLをコピーしました