ネストされたdictやjsonからdataclassを作成したいならpydanticが便利

ネストされたdictやjsonからdataclassを作成したいならpydanticが便利

ネストされたdictやjsonからdataclassを作成するのは面倒くさい

ネストされたdictやjsonからdataclassを作成するのは面倒くさいです. 例えば以下のようなdictがあったとします.

data = {
    "name": "hoge",
    "age": 20,
    "address": {
        "country": "Japan",
        "city": "Tokyo",
        "street": "hoge street",
    },
}

このdictから以下のようなdataclassを作成したいとします.

from dataclasses import dataclass

@dataclass
class Address:
    country: str
    city: str
    street: str

@dataclass
class Person:
    name: str
    age: int
    address: Address

このような時,例えば辞書を展開してdataclassを作成しようとすると以下のようになります.

person = Person(**data)
print(person)
# Person(name='hoge', age=20, address={'country': 'Japan', 'city': 'Tokyo', 'street': 'hoge street'})

見ての通り,Addressも展開してデータクラスにしてほしいのに,dictのままになってしまいます.これをどうにかしようとすると,メソッドを書いたり色々しないといけなく,面倒です.

このような時,pydanticを使うと便利です.

pydanticを使う

pydanticを使うときは,dataclassesの代わりにpydanticのdataclassを使います.

from pydantic.dataclasses import dataclass
# 以下は先程と同じ

これで先ほどのコードを実行すると,以下のようになります.

person = Person(**data)
print(person)
# Person(name='hoge', age=20, address=Address(country='Japan', city='Tokyo', street='hoge street'))

しっかりAddressもdataclassになっています.

その他

TypeAdapter

pydantic v2から追加されたTypeAdapterを使うと,dictやjsonからdataclassを作成する際に,そのまま引数として渡せます. 詳しくはココを参照

from pydantic import TypeAdapter
datas: list[Person] = ...
json: str = ...
# persons = [Person(**data) for data in datas]の代わりに
persons = TypeAdapter(list[Person]).dump_python(datas) # dictの場合
persons = TypeAdapter(list[Person]).dump_json(json) # jsonの場合

BaseModelとdataclass

pydanticにはBaseModelというクラスがあり,dataclassとよく似ていますが,違いもあるようですので,以下の記事を参照して使い分けるのが良いと思います. 参考になるサイト

個人的にはBaseModelじゃないとないメソッドがあったりするので,BaseModelを使っています.

This work is licensed under 
CC BY 4.0