Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将枚举成员序列化为JSON_Python_Json_Python 3.x_Serialization_Enums - Fatal编程技术网

Python 将枚举成员序列化为JSON

Python 将枚举成员序列化为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

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