用JSONEncoder解决Object of type Color is not JSON serializable报错
用json.dumps无法序列化自定义类型,然后报错Object of type Color is not JSON serializable。经过搜索,找到了解决办法,然后写了一个demo记录于此。
不出意外,它可以直接运行并查看效果。
如果你愿意阅读里面的注释,或许能解决一点你的其他问题。
import dataclasses
import enum
import json
class Color(enum.Enum):
Red = "FF0000"
Green = "00FF00"
Blue = "0000FF"
@dataclasses.dataclass
class TestData:
color: Color
vi: int = 0
vf: float = 0.0
vs: str = ""
def json_loads(text: str) -> dict:
""""""
def as_color(dct: dict):
"""仿写自 https://docs.python.org/zh-cn/3.8/library/json.html 网页的 as_complex 的实现"""
assert isinstance(dct, dict)
# 例如 {"__Color__": 1, "Color": "0000FF"}
if len(dct) == 2 and dct.get(f"__{Color.__name__}__") == 1 and dct.get(Color.__name__) in Color._value2member_map_:
return Color(dct[Color.__name__])
return dct
data: dict = json.loads(
text,
object_hook=as_color,
)
return data
def json_dumps(data: dict) -> str:
""""""
# 我最初搜到了 https://blog.csdn.net/qq_43229040/article/details/112306837
# 尝试之后报错 TypeError: json_dumps.<locals>.change_type() got an unexpected keyword argument 'skipkeys'
# 搜索后找到了 https://docs.python.org/zh-cn/3.8/library/json.html 才解决问题,
# 备注: 在 json_dumps 里写 ColorEncoder 是没问题的,
# 不要为了对仗而在 json_loads 里实现 ColorDecoder(json.JSONDecoder) 并使用,
# 你仿照 ColorEncoder 写一个 ColorDecoder 试试就知道了,
class ColorEncoder(json.JSONEncoder):
"""仿写自 https://docs.python.org/zh-cn/3.8/library/json.html 网页的 ComplexEncoder 的实现"""
def default(self, obj):
if isinstance(obj, Color):
# 例如 {"__Color__": 1, "Color": "0000FF"}
return {f"__{Color.__name__}__": 1, Color.__name__: obj.value}
# Let the base class default method raise the TypeError
return json.JSONEncoder.default(self, obj)
text: str = json.dumps(
data,
cls=ColorEncoder,
)
return text
if __name__ == "__main__":
data1 = TestData(color=Color.Red, vi=3, vf=1.414, vs="string")
dict1 = data1.__dict__
print("dict1:", dict1) # dict1: {'color': <Color.Red: 'FF0000'>, 'vi': 3, 'vf': 1.414, 'vs': 'string'}
try:
json.dumps(dict1)
except Exception as ex:
print(ex) # Object of type Color is not JSON serializable
text1: str = json_dumps(dict1)
print("text1:", text1) # text1: {"color": {"__Color__": 1, "Color": "FF0000"}, "vi": 3, "vf": 1.414, "vs": "string"}
dict2 = json_loads(text1)
print("dict2:", dict2) # dict2: {'color': <Color.Red: 'FF0000'>, 'vi': 3, 'vf': 1.414, 'vs': 'string'}
data2 = TestData(**dict2)
assert data1 == data2 # 断言通过