是否可以在没有将编码器传递给json.dumps()的情况下在json中转储枚举?

问题描述 投票:7回答:4

我可以通过以下示例总结我的问题:

from enum import Enum
import json

class FooBarType(Enum):
    standard = 0
    foo = 1
    bar = 2

dict = {'name': 'test', 'value': 'test', 'type': FooBarType.foo}

json.dumps(dict)

TypeError: <FooBarType.foo: 1> is not JSON serializable

我收到类型错误,因为枚举不是JSON可序列化的。

我主要是实现一个JsonEncoder并将其添加到json.dumps()调用但我无法更改json.dumps()调用的行。

所以,我的问题是:是否可以在没有将编码器传递给json.dumps()的情况下在json中转储枚举,而是通过在FooBarType枚举中添加类方法?

我希望提取以下json:

{'name': 'test', 'value': 'test', 'type': 'foo'}

要么

{'name': 'test', 'value': 'test', 'type': 1}
python json python-2.7 enums
4个回答
3
投票

我不认为这有很好的方法,你将失去Enum的功能。

最简单的选择:不要枚举Enum:

class FooBarType:
    standard = 0
    foo = 1
    bar = 2

dict = {'type': FooBarType.foo}
json.dumps(dict)

你还可以做什么:

class EnumIntValue(int):
    def __new__(cls, name, value):
        c = int.__new__(cls, int(value))
        c.name = name
        return c
    def __repr__(self):
        return self.name
    def __str__(self):
        return self.name

class FooBarType:
    standard = EnumIntValue('standard',0)
    foo = EnumIntValue('foo',0)
    bar = EnumIntValue('bar',2)

dict = {'type': FooBarType.foo}
json.dumps(dict)

这实际上会给你

{"type": foo}

因此不是真正有效的json,但你可以玩它来满足你的需求!


13
投票

尝试:

from enum import Enum

# class StrEnum(str, Enum):
#     """Enum where members are also (and must be) strs"""

class Color(str, Enum):
    RED = 'red'
    GREEN = 'green'
    BLUE = 'blue'


data = [
    {
        'name': 'car',
        'color': Color.RED,
    },
    {
        'name': 'dog',
        'color': Color.BLUE,
    },
]

import json
print(json.dumps(data))

结果:

[
    {
        "name": "car",
        "color": "red"
    },
    {
        "name": "dog",
        "color": "blue"
    }
]

3
投票

可悲的是,在JSON中没有直接支持Enum

最接近的自动支持是使用IntEnumenum34也支持),然后json将你的enums视为ints;当然,解码它们会给你一个int回来,但是如果不指定你的编码器/解码器那就好了。


3
投票

只是将方法添加到FooBarType枚举将不会做你想要的。

正如我在评论中提到的那样,你可以使用Making object JSON serializable with regular encoder问题的部分答案来修补json模块,这样它就会返回Enum成员的名字(或值)。我假设您正在使用Ethan Furman等人的enums34模块,该模块被反向移植到Python 2.7,因为该版本没有内置它 - 它成为了standard library in Python 3.4的一部分。

请注意,即使您无法更改json.dumps()调用发生的行,只要在应用补丁后发生这种情况,这将会起作用。这是因为Python通常在import中缓存sys.modulesed模块,即每次在单独的脚本中使用它们时都不会重新加载 - 因此对它们进行的任何更改都是“粘性的”并保持有效。

因此,对于您想要做的事情,首先要创建自己的模块来制作补丁。例如:make_enum_json_serializable.py

""" Module that monkey-patches the json module when it's imported so
JSONEncoder.default() automatically checks to see if the object being encoded
is an instance of an Enum type and, if so, returns its name.
"""
from enum import Enum
from json import JSONEncoder

_saved_default = JSONEncoder().default  # Save default method.

def _new_default(self, obj):
    if isinstance(obj, Enum):
        return obj.name  # Could also be obj.value
    else:
        return _saved_default

JSONEncoder.default = _new_default # Set new default method.

然后,在您自己的脚本中,您需要做的就是添加一行:

from enum import Enum
import json
import make_enum_json_serializable  # ADDED

class FooBarType(Enum):
    standard = 0
    foo = 1
    bar = 2

a_dict = {'name': 'spam', 'value': 42, 'type': FooBarType.foo}

print(json.dumps(a_dict))

输出:

{"type": "foo", "name": "spam", "value": 42}
© www.soinside.com 2019 - 2024. All rights reserved.