一尘不染

将Enum成员序列化为JSON

json

如何将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

我该如何避免呢?


阅读 544

收藏
2020-07-27

共1个答案

一尘不染

如果您想将任意enum.Enum成员编码为JSON,然后将其解码为相同的枚举成员(而不是简单的枚举成员的value属性),则可以编写一个自定义JSONEncoder类,并使用一个解码函数作为object_hook参数传递给json.load()or来实现。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函数依赖于已使用EnumEncoder或类似行为进行编码的JSON 。

对成员的限制PUBLIC_ENUMS是必要的,以避免使用恶意制作的文本来(例如)欺骗调用代码以将私有信息(例如,应用程序使用的密钥)保存到不相关的数据库字段中,然后从该字段中将其公开(请参阅http://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'}
2020-07-27