Python 将枚举成员序列化为JSON
如何将PythonPython 将枚举成员序列化为JSON,python,json,python-3.x,serialization,enums,Python,Json,Python 3.x,Serialization,Enums,如何将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 TypeError:不可序列化JSO
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
TypeError:不可序列化JSON
如何避免这种情况?正确答案取决于您打算如何处理序列化版本 如果要反序列化回Python,请参阅 如果您的序列化版本将使用另一种语言,那么您可能希望使用
IntEnum
,它将自动序列化为相应的整数:
from enum import IntEnum
import json
class Status(IntEnum):
success = 0
failure = 1
json.dumps(Status.success)
这将返回:
'0'
如果要将任意
enum.enum
成员编码为JSON,然后解码
它作为同一个枚举成员(而不仅仅是枚举成员的值
属性),您可以通过编写自定义类和解码函数作为对象钩子
参数传递给或:
as_enum
函数依赖于使用enumcoder
编码的JSON,或者与之行为相同的东西
对PUBLIC_enum
成员的限制是必要的,以避免恶意制作的文本被用于(例如)诱骗调用代码将私人信息(例如,应用程序使用的密钥)保存到不相关的数据库字段,然后从该字段将其公开(请参阅)
用法示例:
>>> 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'}
>数据={
…“行动”:“泡沫状”,
…“状态”:状态。成功
... }
>>>text=json.dumps(数据,cls=EnumEncoder)
>>>正文
“{”状态“{”{”{uuuuuu枚举“}”状态.成功“}”,操作“}”
>>>loads(text,object\u hook=as\u enum)
{'status':,'action':'frobnite'}
我喜欢Zero Piraeus的答案,但由于使用了亚马逊Web服务(AWS)的API(称为Boto),我对它做了一些修改
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)
我希望这对别人有帮助。我知道这很旧,但我觉得这会帮助别人。我刚刚解决了这个问题,发现如果使用字符串枚举,将枚举声明为
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对象。如果您不想创建自定义JSONeCoder,这是一个很好的选择。如果您使用的是jsonpickle
最简单的方法如下所示
从枚举导入枚举
导入jsonpickle
@jsonpickle.handlers.register(枚举,base=True)
类EnumHandler(jsonpickle.handlers.BaseHandler):
def展平(自身、obj、数据):
返回obj.value#转换为json友好格式
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
类状态(枚举):
成功=0
错误=1
类SimpleClass:
通过
简单类=简单类()
simple_class.status=status.success
json=jsonpickle.encode(简单类,unpicklable=False)
打印(json)
Json序列化之后,您将获得预期的{“状态”:0}
而不是
{"status": {"__objclass__": {"py/type": "__main__.Status"}, "_name_": "success", "_value_": 0}}
在Python 3.7中,可以只使用
json.dumps(enum_obj,default=str)
这对我来说很有效:
class Status(Enum):
success = 0
def __json__(self):
return self.value
不需要改变其他任何事情。显然,如果以后要将序列化的值转换回枚举,您只需要从中获取值,并且需要做一些其他工作。您只需要从
str
或int
类继承:
from enum import Enum, unique
@unique
class StatusEnum(int, Enum):
pending: int = 11
approved: int = 15
declined: int = 266
就这样,它将使用任何JSON编码器序列化。谢谢,零!很好的示例。如果模块中有代码(例如enumencoder.py),则必须将解析的类从JSON导入dict。例如,在本例中,必须将类状态导入模块enumencoder.py。我关心的不是恶意调用代码,而是对web服务器的恶意请求。正如您所提到的,私有数据可以在响应中公开,也可以用于操纵代码流。谢谢你更新你的答案。如果主代码示例是安全的,那就更好了。@JaredDeckard抱歉,你是对的,我错了。我已经相应地更新了答案。谢谢你的意见!这是很有教育意义的(也是很有教育意义的)。有没有办法用encoder类“注释”enum,以便默认情况下使用编码器?@AShelly:这个问题被标记为
Python3.4
,这个答案是3.4+特定的.Perfect。如果枚举是一个字符串,您将使用EnumMeta
而不是IntEnum
@bholagabbar:不,您将使用Enum
,可能与str
混合--类MyStrEnum(str,Enum):…
@bholagabbar,很有趣。您应该将您的解决方案作为答案发布。我会避免直接从EnumMeta
继承,因为它只打算作为元类。相反,请注意,IntEnum
的实现,您可以通过类strengum(str,Enum)实现str
的相同功能:…
。谢谢。尽管我主要反对多重继承,但这很好,这就是我的看法。不需要额外的编码器:)@madjardi,你能详细说明你遇到的问题吗?我从未遇到过字符串值与枚举中属性名称不同的问题。我误解了你的评论吗?classloglevel(str,Enum):DEBUG='Баааааааааааааа'INFO=/code>在这种情况下Enum with str
不能正常工作(例如,你也可以对其他基类型使用这个技巧(我不知道如何在注释中格式化,但要点很清楚:square=1 circle=2“在不需要编码器的情况下工作得很好。谢谢,这是一个很好的方法!这个str mixin可能会产生意想不到的副作用:看。我在描述这个神奇方法的文章中没有看到任何东西。你在使用其他JSON库吗
from enum import Enum, unique
@unique
class StatusEnum(int, Enum):
pending: int = 11
approved: int = 15
declined: int = 266