我可以通过以下示例总结我的问题:
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}
我不认为这有很好的方法,你将失去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,但你可以玩它来满足你的需求!
尝试:
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"
}
]
只是将方法添加到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.modules
ed模块,即每次在单独的脚本中使用它们时都不会重新加载 - 因此对它们进行的任何更改都是“粘性的”并保持有效。
因此,对于您想要做的事情,首先要创建自己的模块来制作补丁。例如: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}