Data ClassesはPython3.7からの新機能です。その名の通りデータを保持するためのクラスを簡潔に記述することができます。
Dataclassはdataclasses_json
パッケージを使うことによりお手軽にjson形式へ変換できます。
json形式でシリアライズできると人間が直接編集したり非Pythonの外部アプリケーションにデータを渡したりする際にとても都合がよいです。
※追記:2022年現在ではpydantic.dataclasses.dataclassも有力な選択肢です
[目次]
インストール
pip install dataclasses_json
シンプルなDataclassの場合
PermissionConfig
は何かのアプリケーションの権限設定をイメージしたサンプルクラスです。
dataclasses_json
モジュールを Dataclassへ適用するには通常の@dataclass
デコレータに@dataclass_json
デコレータを重ねるだけでOKです。
from datetime import datetime from dataclasses import dataclass from typing import List, Dict from uuid import uuid4, UUID from dataclasses_json import dataclass_json @dataclass_json @dataclass class PermissionConfig: uid : UUID = uuid4() updated: datetime = datetime.now() owner: str = None users : List[str] = None user_group: Dict[str, List[str]] = None note: str = "ensure_asciiをFalseにしないと日本語は文字化けする"
datetime.datetime
型やuuid.UUID
型にも対応しているのが嬉しいところです。
ではこのクラスへ具体的なデータを格納していきます。
>>> config = PermissionConfig() >>> config.owner = "Alice" >>> config.users = ["Bob", "Carol", "Dave", "Eve"] >>> config.user_group = {"admin": ["Alice", "Bob"], "user":["Carol", "Dave", "Eve"]} >>> print(config)
PermissionConfig(uid=UUID('f429b01b-3d72-416e-8909-9370b4a34770'), updated=datetime.datetime(2019, 11, 24, 3, 10, 13, 453036), owner='Alice', users=['Bob', 'Carol', 'Dave', 'Eve'], user_group={'admin': ['Alice', 'Bob'], 'user': ['Carol', 'Dave', 'Eve']}, note='ensure_asciiをFalseにしないと日本語は文字化けする')
ここまでは普通にDataclassですね。Json形式への変換は以下のように行います。
>>> config_json = config.to_json(indent=4, ensure_ascii=False) >>> print(type(config_json) <class 'str'> >>> print(config_json)
{ "uid": "f429b01b-3d72-416e-8909-9370b4a34770", "updated": 1574532613.453036, "owner": "Alice", "users": [ "Bob", "Carol", "Dave", "Eve" ], "user_group": { "admin": [ "Alice", "Bob" ], "user": [ "Carol", "Dave", "Eve" ] }, "note": "ensure_asciiをFalseにしないと日本語は文字化けする" }
ensure_ascii=False
にしないと日本語が文字化けすることに注意。
さらにこのJson形式文字列からPermissionConfig
を復元します。
>>> config_from_json = PermissionConfig.from_json(setting_json)
>>> print(config_from_json)
PermissionConfig(uid=UUID('c6c0df3d-f702-436a-830a-5b51ec3c909b'), updated=datetime.datetime(2019, 11, 24, 1, 56, 25, 67129, tzinfo=datetime.timezone(datetime.timedelta(seconds=32400), '???? (?W?\x80??)')), owner='Alice', users=['Bob', 'Carol', 'Dave', 'Eve'], user_group={'admin': ['Bob', 'Alice'], 'user': ['Carol', 'Dave', 'Eve']}, note='')
正しく型を復元できているか確認します。
>>>print(type(config_from_json.uid), type(config_from_json.updated), type(config_from_json.owner), type(config_from_json.users), type(config_from_json.user_group))
<class 'uuid.UUID'> <class 'datetime.datetime'> <class 'str'> <class 'list'> <class 'dict'>
完璧ですね。
ネストしたDataclassの場合
Dataclassを保持するDataclassも使用可能です。
以下は先ほどのPermissionConfig
がPerson
データクラスを保持する例です。
@dataclass_json @dataclass class Person: name: str age: int @dataclass_json @dataclass class PermissionConfig: uid : UUID = uuid4() updated: datetime = datetime.now() owner: Person = None users : List[Person] = None user_group: Dict[str, List[Person]] = None note: str = "ensure_asciiをFalseにしないと日本語は文字化けする"
先ほどと同様にデータを格納します。
>>> config = PermissionConfig() >>> config.owner = Person(name="Alice", age=22) >>> config.users = [Person(name="Bob", age=22), Person(name="Carol", age=35), Person(name="Dave", age=42), Person(name="Eve", age=27)] >>> config.user_group = {"admin": [Person(name="Alice", age=22), Person(name="Bob", age=22)], "user":[Person(name="Carol", age=35), Person(name="Dave", age=42), Person(name="Eve", age=27)]} >>> config_json = config.to_json(indent=4, ensure_ascii=False) >>> print(type(config_json))
{ "uid": "d683282a-0cb1-455f-a822-9d9d3cbca3f1", "updated": 1574533718.833665, "owner": { "name": "Alice", "age": 22 }, "users": [ { "name": "Bob", "age": 22 }, { "name": "Carol", "age": 35 }, { "name": "Dave", "age": 42 }, { "name": "Eve", "age": 27 } ], "user_group": { "admin": [ { "name": "Alice", "age": 22 }, { "name": "Bob", "age": 22 } ], "user": [ { "name": "Carol", "age": 35 }, { "name": "Dave", "age": 42 }, { "name": "Eve", "age": 27 } ] }, "note": "ensure_asciiをFalseにしないと日本語は文字化けする" }
>>> config_from_json = PermissionConfig.from_json(config_json) >>> print(config_from_json)
PermissionConfig(uid=UUID('aa2f5ff0-eee8-4e20-b711-ead988d90844'), updated=datetime.datetime(2019, 11, 24, 2, 11, 55, 430387, tzinfo=datetime.timezone(datetime.timedelta(seconds=32400), '???? (?W?\x80??)')), owner=Person(name='Alice', age=22), users=[Person(name='Bob', age=22), Person(name='Carol', age=35), Person(name='Dave', age=42), Person(name='Eve', age=27)], user_group={'admin': [Person(name='Alice', age=22), Person(name='Bob', age=22)], 'user': [Person(name='Carol', age=35), Person(name='Dave', age=42), Person(name='Eve', age=27)]}, note='ensure_asciiをFalseにしないと日本語は文字化けする')
OK!!