1. ホーム
  2. python

[解決済み] EnumのメンバをJSONにシリアライズする

2022-06-13 10:24:13

質問

Pythonの Enum メンバをJSONにシリアライズして、結果のJSONをPythonオブジェクトにデシリアライズして戻すことができますか?

例えば、このようなコードです。

from enum import Enum    
import json

class Status(Enum):
    success = 0

json.dumps(Status.success)

の結果は、エラーになります。

TypeError: <Status.success: 0> is not JSON serializable

どうすれば回避できますか?

どのように解決するのですか?

をエンコードする場合、任意の enum.Enum メンバをJSONにエンコードし、それをデコードしたい場合 を同じ enum メンバとしてデコードしたい場合 (単に enum メンバの value 属性ではなく)、カスタムの JSONEncoder クラスを作成し、デコード関数を object_hook への引数として渡すデコード関数です。 json.load() または json.loads() :

PUBLIC_ENUMS = {
    'Status': Status,
    # ...
}

class EnumEncoder(json.JSONEncoder):
    def default(self, obj):
        if type(obj) in PUBLIC_ENUMS.values():
            return {"__enum__": str(obj)}
        return json.JSONEncoder.default(self, obj)

def as_enum(d):
    if "__enum__" in d:
        name, member = d["__enum__"].split(".")
        return getattr(PUBLIC_ENUMS[name], member)
    else:
        return d

as_enum 関数は、JSON が EnumEncoder またはそれと同じ振る舞いをする何かでエンコードされていることに依存します。

のメンバーへの制限は PUBLIC_ENUMS は、悪意を持って細工されたテキストが、例えば、呼び出し元のコードを騙してプライベートな情報 (例えば、アプリケーションで使われる秘密鍵) を無関係のデータベースフィールドに保存させ、そこから公開されることを避けるために必要です (詳しくは https://chat.stackoverflow.com/transcript/message/35999686#35999686 ).

使用例です。

>>> data = {
...     "action": "frobnicate",
...     "status": Status.success
... }
>>> text = json.dumps(data, cls=EnumEncoder)
>>> text
'{"status": {"__enum__": "Status.success"}, "action": "frobnicate"}'
>>> json.loads(text, object_hook=as_enum)
{'status': <Status.success: 0>, 'action': 'frobnicate'}