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)
代表的なものを簡単に紹介します。
パラメータ | デフォルト | 説明 |
init | True | __init__を生成するか |
eq | True | 比較メソッド(__eq__)を自動で生成するか |
frozen | False | 変更不可にするか。いわゆるイミュータブル |
フィールド定義
dataclass のフィールド定義する場合には”dataclasses.field”を使います。
使わなくても定義は可能ですが、必要な場合もあるので個人的には統一して使うようにしています。
パラメータ | デフォルト | 説明 |
default | MISSING | デフォルト値。Noneを指定するとインスタンス生成時パラメータ不要になる |
init | True | __init__にこのフィールドを含めるか |
compare | True | 比較メソッドにこのフィールドを含めるか |
型定義
フィールドの型を定義するにはヒントを付けます。
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)
その他、データクラスはいろいろ便利に使えるので公式や記事を参照して使ってみてください。