首页 > 解决方案 > 组合多个 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))

标签: pythonjsonpython-3.x

解决方案


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"}'


推荐阅读