如何让json.dumps/loads支持传入Encoder/Decoder实例而非类
能否让json.dumps/loads支持接收Encoder/Decoder实例而非类作为参数?
问题背景
参考如下自定义JSON编码器的基础示例:
import json from typing import Any class MyNumber: def __init__(self, num): self.num = num class MultEncoder(json.JSONEncoder): """编码MyNumber实例时做乘法处理""" def default(self, o: Any) -> Any: if isinstance(o, MyNumber): return o.num*2 return super().default(o)
上述代码的基础运行效果:
>>> json.dumps({"a": MyNumber(5)}, cls=MultEncoder) '{"a": 10}'
当需要动态配置编码时的乘数因子时,尝试编写带自定义初始化参数的编码器:
class MultEncoder(json.JSONEncoder): """编码MyNumber实例时按指定因子做乘法处理""" def __init__(self, factor, *args, **kwargs): self.factor = factor super().__init__(*args, **kwargs) def default(self, o: Any) -> Any: if isinstance(o, MyNumber): return o.num*self.factor return super().default(o)
执行json.dumps({"a": MyNumber(5)}, cls=MultEncoder(7))时会抛出如下错误:
TypeError: 'MultEncoder' object is not callable
报错原因是json.dumps的cls参数要求传入类对象,而非类的实例。
已知约束
- 无法自定义封装
my_json_dumps/my_json_loads包装函数,仅能控制调用json.dumps、json.loads时传入的编码器/解码器类 - 实际业务场景中,编码器/解码器需要读取数据库连接凭证及其他动态配置信息,无法将参数硬编码在类中
可行实现方案
不需要修改标准库json模块逻辑,也不需要封装dumps/loads方法,通过类工厂+闭包动态生成绑定了配置参数的编码器/解码器类即可,完全兼容原生cls参数的传参要求。
编码器实现
编写接收动态配置、返回定制化Encoder子类的工厂函数:
def build_mult_encoder(factor: int): # 内部定义绑定了配置参数的编码器子类 class ConfiguredMultEncoder(json.JSONEncoder): def default(self, o: Any) -> Any: if isinstance(o, MyNumber): return o.num * factor return super().default(o) return ConfiguredMultEncoder
调用方式
直接将工厂生成的类传入cls参数即可,无需传入实例:
>>> json.dumps({"a": MyNumber(5)}, cls=build_mult_encoder(7)) '{"a": 35}' >>> json.dumps({"a": MyNumber(5)}, cls=build_mult_encoder(3)) '{"a": 15}'
如果需要读取数据库凭证等复杂动态配置,只需要将工厂函数的入参替换为对应配置项即可,所有配置会在生成类时绑定到闭包作用域中,编码器实例化时无需额外传参,完全符合json模块对cls参数的类型要求。
Decoder的动态配置实现逻辑完全一致:编写接收动态配置的类工厂函数,返回定制后的
json.JSONDecoder子类,直接传入json.loads的cls参数即可正常使用。
内容的提问来源于stack exchange,提问作者actual_panda
相关产品推荐
相关产品推荐

