将枚举成员序列化为JSON

2024-04-26 12:12:46 发布

您现在位置:Python中文网/ 问答频道 /正文

如何将PythonEnum成员序列化为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

我怎样才能避免呢?


Tags: 对象代码fromimportjson序列化status成员
3条回答

如果要将任意enum.Enum成员编码为JSON,然后解码 它作为同一个枚举成员(而不仅仅是枚举成员的value属性),您可以通过编写一个自定义的^{}类和一个解码函数作为object_hook参数传递给^{}^{}

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'}

我知道这是旧的,但我觉得这会帮助人们。我刚刚解决了这个问题,发现如果您使用的是字符串枚举,那么将枚举声明为str的子类对于几乎所有情况都很有效:

import json
from enum import Enum

class LogLevel(str, Enum):
    DEBUG = 'DEBUG'
    INFO = 'INFO'

print(LogLevel.DEBUG)
print(json.dumps(LogLevel.DEBUG))
print(json.loads('"DEBUG"'))
print(LogLevel('DEBUG'))

将输出:

LogLevel.DEBUG
"DEBUG"
DEBUG
LogLevel.DEBUG

如您所见,加载JSON会输出字符串DEBUG,但很容易将其返回到LogLevel对象中。如果不想创建自定义JSONEncoder,这是一个不错的选择。

正确的答案取决于您打算如何处理序列化版本。

如果要取消对Python的序列化,请参见Zero's answer

如果您的序列化版本将要使用另一种语言,则可能需要使用IntEnum,它将自动序列化为相应的整数:

from enum import IntEnum
import json

class Status(IntEnum):
    success = 0
    failure = 1

json.dumps(Status.success)

这将返回:

'0'

相关问题 更多 >