python - 组合多个 JSON 编码器
问题描述
假设您有多个编码器,如下所示:
class JsonDataClassEncoder(json.JSONEncoder):
"""
Supports dataclasses
"""
def default(self, o):
if dataclasses.is_dataclass(o):
return dataclasses.asdict(o)
return super().default(o)
class JsonEnumEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Enum):
return obj.name
return super().default(obj)
有没有办法将它们组合起来,而不是对它们进行子类化,这样就可以使用
json.dumps(opj, cls=MultipleJsonEncoders(JsonEnumEncoder, JsonDataClassEncoder))
解决方案
class MultipleJsonEncoders():
"""
Combine multiple JSON encoders
"""
def __init__(self, *encoders):
self.encoders = encoders
self.args = ()
self.kwargs = {}
def default(self, obj):
for encoder in self.encoders:
try:
return encoder(*self.args, **self.kwargs).default(obj)
except TypeError:
pass
raise TypeError(f'Object of type {obj.__class__.__name__} is not JSON serializable')
def __call__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
enc = json.JSONEncoder(*args, **kwargs)
enc.default = self.default
return enc
用法
import json
import enum
import datetime
class JsonDateEncoder(json.JSONEncoder):
"""JSON serializer for objects not serializable by default json code"""
def default(self, o):
if isinstance(o, (datetime.datetime, datetime.date)):
return o.isoformat()
return super().default(o)
class JsonEnumEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, Enum):
return o.name
return super().default(o)
class Enumm(enum.Enum):
X = enum.auto()
obj = {'time': datetime.datetime.now(), 'enum': Enumm.X}
encoder = MultipleJsonEncoders(JsonDateEncoder, JsonEnumEncoder)
In [502]: json.dumps(obj, cls=encoder)
Out[502]: '{"time": "2020-12-23T08:51:43.646022", "enum": "X"}'
推荐阅读
- ruby-on-rails - Rails 管理员未列出记录
- excel - 创建与另一个单元格上设置的值一样多的行
- javascript - 如何根据 typescript 中传递的参数设置属性的类型?
- flask - flaskform 为字符串字段中的值插入数据
- node.js - NodeJS res.status 不是一个函数
- vue.js - Vue - 从组件中检索事件和 v-model
- java - Android:从“下载”文件夹中删除下载的文件快捷方式
- ios - 应用程序因 self.tableView.deleteRows 崩溃(在:[indexPath],与:.fade)
- python - 如何有条件地更改散点图点形状?
- laravel - Laravel 存储文件请求适用于本地主机,但不适用于生产