0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

dataclasses-jsonでPythonでも手軽にキャメルケースのJSONを扱う

Posted at

はじめに

n番煎じ感が否めませんが、Pythonでjsonを扱う際にdataclass×dataclasses-jsonの組み合わせが便利だったので紹介します。

結局何が便利?

  • JSONとの変換がto_json()メソッドとfrom_json()メソッドだけで行える
    • to_dict()メソッドとfrom_dict()メソッドにより辞書型に変換することも可能です
  • ネストされたクラスでも下の階層まで各クラスに展開してくれる
  • スネークケースとキャメルケース(やパスカルケースなど)を自動的に変換してくれる
    • Pythonはスネークケース、jsonはキャメルケース、というパターンが多いため、この機能によって命名規則に困らなくなります
余談 後から知ったのですが、Pydanticでも同様の機能が提供されているようです

準備

環境

今回テストした環境は以下の通りです

  • Python 3.12.0
  • dataclasses-json 0.6.7

dataclasses-jsonはpipでインストールすることが可能です

$ pip install dataclasses-json

dataclass自体に関しては既に多くの記事で詳しく紹介されているため、本記事では特に取り扱いません

実践

クラスの用意

今回は以下のようなネストされたFamilyクラスを使用して具体的に見ていきます

変数名はスネークケースで宣言されていますが、クラスの定義の前に@dataclass_json(letter_case=LetterCase.CAMEL)デコレータがついています

このデコレータの引数で記法を指定することによって自動的にスネークケースとキャメルケースを変換してくれます

from dataclasses import dataclass
from dataclasses_json import dataclass_json, LetterCase

@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass
class Address:
    postal_code: str
    country: str
    city: str
    street: str

@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass
class Person:
    first_name: str
    last_name: str
    age: int
    address: Address

@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass
class Family:
    members: list[Person]

デコレータのLetterCaseについて

CAMELケース以外にも、SNAKE、KEBAB、PASCALが用意されているようです
※何も指定しなかった場合は変数名に使用しているケースがそのまま適用されます

to_json

オブジェクトをJSONに変換するにはdataclass_jsonで追加される.to_json()メソッドを使用します

family_obj = Family(
    members=[
        Person(
            first_name='hoge',
            last_name='fuga',
            age=20,
            address=Address(
                postal_code='100-0000',
                country='Japan',
                city='Tokyo',
                street='hoge street'
            )
        ),
        Person(
            first_name='foo',
            last_name='bar',
            age=30,
            address=Address(
                postal_code='200-0000',
                country='Japan',
                city='Osaka',
                street='foo street'
            )
        )
    ]
)
json_str = family_obj.to_json(indent=4)
print(json_str)
# output
# {
#     "members": [
#         {
#             "firstName": "hoge",
#             "lastName": "fuga",
#             "age": 20,
#             "address": {
#                 "postalCode": "100-0000",
#                 "country": "Japan",
#                 "city": "Tokyo",
#                 "street": "hoge street"
#             }
#         },
#         {
#             "firstName": "foo",
#             "lastName": "bar",
#             "age": 30,
#             "address": {
#                 "postalCode": "200-0000",
#                 "country": "Japan",
#                 "city": "Osaka",
#                 "street": "foo street"
#             }
#         }
#     ]
# }

to_jsonの引数でindentを4に指定することで整形して出力してくれます
(この辺りはjsonモジュールのdumpsと同様ですね)

注目すべきは出力されたJSON文字列のキー名がキャメルケースになっていることです
先ほど、クラスの定義時にデコレータでキャメルケースを指定しておいたことで、自動的に変換された状態でJSON文字列になってくれています

これでデフォルトの命名規則がキャメルケースのTypeScriptなどとJSONでやり取りする時も困りませんね

from_json

逆にJSON文字列からオブジェクトに変換する際はfrom_dict()メソッドを使用します

new_json_str = '''
{
    "members": [
        {
            "firstName": "hogehoge",
            "lastName": "fugafuga",
            "age": 30,
            "address": {
                "postalCode": "300-0000",
                "country": "Japan",
                "city": "Fukuoka",
                "street": "hogehoge street"
            }
        },
        {
            "firstName": "foobar",
            "lastName": "barfoo",
            "age": 40,
            "address": {
                "postalCode": "400-0000",
                "country": "Japan",
                "city": "Nagoya",
                "street": "foobar street"
            }
        }
    ]
}
'''
new_family_obj = Family.from_json(new_json_str)
print(new_family_obj)
# output
# Family(
#     members=[
#         Person(
#             first_name='hogehoge', last_name='fugafuga', age=30,
#             address=Address(postal_code='300-0000', country='Japan', city='Fukuoka', street='hogehoge street')
#         ),
#         Person(
#             first_name='foobar', last_name='barfoo', age=40,
#             address=Address(postal_code='400-0000', country='Japan', city='Nagoya', street='foobar street')
#         )
#     ]
# )

新しくnew_json_strを用意し、クラス名.from_jsonの形で呼び出します

今回はJSON文字列⇒オブジェクトなので、キャメルケース⇒スネークケースに自動的に変換されていますね
ちなみに、JSON文字列内のキーにスネークケースが含まれていても問題なく変換可能でした

to_dict

ここまではオブジェクトとJSONとの変換でしたが、dataclasses-jsonでは辞書型との変換もサポートされています
まずはオブジェクトを辞書型に変換するto_dict()メソッドです

print(family_obj)
# output
# Family(
#   members=[
#       Person(
#           first_name='hoge', last_name='fuga', age=20,
#           address=Address(postal_code='100-0000', country='Japan', city='Tokyo', street='hoge street')
#       ),
#       Person(
#           first_name='foo', last_name='bar', age=30,
#           address=Address(postal_code='200-0000', country='Japan', city='Osaka', street='foo street')
#       )
#   ]
# )
family_dict = family_obj.to_dict()
print(family_dict)
# output
# {
#     'members': [
#         {
#             'firstName': 'hoge', 'lastName': 'fuga', 'age': 20,
#             'address': {'postalCode': '100-0000', 'country': 'Japan', 'city': 'Tokyo', 'street': 'hoge street'}
#         },
#         {
#             'firstName': 'foo', 'lastName': 'bar', 'age': 30,
#             'address': {'postalCode': '200-0000', 'country': 'Japan', 'city': 'Osaka', 'street': 'foo street'}
#         }
#     ]
# }

from_dict

from_dict()メソッドで辞書型からオブジェクトに変換できます

new_family_dict = {
    'members': [
        {
            'firstName': 'hogehoge', 'lastName': 'fugafuga', 'age': 30,
            'address': {'postalCode': '300-0000', 'country': 'Japan', 'city': 'Fukuoka', 'street': 'hogehoge street'}
        },
        {
            'firstName': 'foobar', 'lastName': 'barfoo', 'age': 40,
            'address': {'postalCode': '400-0000', 'country': 'Japan', 'city': 'Nagoya', 'street': 'foobar street'}
        }
    ]
}
new_family_obj = Family.from_dict(new_family_dict)
print(new_family_obj)
# output
# Family(
#     members=[
#         Person(
#             first_name='hogehoge', last_name='fugafuga', age=30,
#             address=Address(postal_code='300-0000', country='Japan', city='Fukuoka', street='hogehoge street')
#         ),
#         Person(
#             first_name='foobar', last_name='barfoo', age=40,
#             address=Address(postal_code='400-0000', country='Japan', city='Nagoya', street='foobar street')
#         )
#     ]
# )

from_dict()メソッドでもfrom_json()メソッドと同様に、元の辞書型がキャメルケースではなくスネークケースでも問題なく変換できました

まとめ

  • dataclass定義時にdataclass_jsonデコレータを付与する
    • 引数のletter_caseで変換時の記法を指定できる
  • オブジェクトから変換
    • to_json()メソッドやto_dict()メソッド
  • オブジェクトに変換
    • from_json()メソッドやfrom_dict()メソッド

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?