问题:将Enum成员序列化为JSON
如何将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
我该如何避免呢?
回答 0
如果您想将任意enum.Enum成员编码为JSON,然后将其解码为相同的enum成员(而不是简单的enum成员的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'}
回答 1
我知道这很老,但我认为这会对人们有所帮助。我刚刚经历了这个确切的问题,发现您是否使用字符串枚举,将您的枚举声明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,则是一个不错的选择。
回答 2
正确答案取决于您打算对序列化版本进行的处理。
如果您要反序列化回Python,请参见Zero的答案。
如果您的序列化版本将要使用另一种语言,那么您可能想使用IntEnum代替,它将自动序列化为相应的整数:
from enum import IntEnum
import json
class Status(IntEnum):
    success = 0
    failure = 1
json.dumps(Status.success)
这将返回:
'0'
回答 3
在Python 3.7中,只能使用
json.dumps(enum_obj, default=str)
回答 4
我喜欢Zero Piraeus的回答,但是对它进行了稍作修改,以便使用称为Boto的Amazon Web Services(AWS)的API。
class EnumEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Enum):
            return obj.name
        return json.JSONEncoder.default(self, obj)
然后,我将此方法添加到我的数据模型中:
    def ToJson(self) -> str:
        return json.dumps(self.__dict__, cls=EnumEncoder, indent=1, sort_keys=True)
我希望这可以帮助别人。
回答 5
如果您使用的jsonpickle是最简单的方法,则应如下所示。
from enum import Enum
import jsonpickle
@jsonpickle.handlers.register(Enum, base=True)
class EnumHandler(jsonpickle.handlers.BaseHandler):
    def flatten(self, obj, data):
        return obj.value  # Convert to json friendly format
if __name__ == '__main__':
    class Status(Enum):
        success = 0
        error = 1
    class SimpleClass:
        pass
    simple_class = SimpleClass()
    simple_class.status = Status.success
    json = jsonpickle.encode(simple_class, unpicklable=False)
    print(json)
在Json序列化之后,您将获得预期的{"status": 0}而不是
{"status": {"__objclass__": {"py/type": "__main__.Status"}, "_name_": "success", "_value_": 0}}
回答 6
这为我工作:
class Status(Enum):
    success = 0
    def __json__(self):
        return self.value
不必更改其他任何内容。显然,您只会从中获得该值,并且如果您想稍后将序列化的值转换回枚举,则需要做一些其他工作。
