Как сделать simplejson сериализуемым классом - PullRequest
7 голосов
/ 28 января 2011

У меня есть определенный класс

class A:
    def __init__(self):
        self.item1 = None
    def __repr__(self):
        return str(self.__dict__)

когда я делаю:

>>> import simplejson
>>> myA = A()
>>> simplejson.dumps(myA)
TypeError: {'item1': None} is not JSON serializable

Я не могу найти причину почему.

Нужно ли добавлять какой-либо конкретный метод в A для simplejson для сериализации моего объекта класса?

Ответы [ 2 ]

10 голосов
/ 28 января 2011

Вы не можете сериализовать произвольные объекты с simplejson.Вам нужно передать default и object_hook на dump и load.Вот пример:

class SerializerRegistry(object):
    def __init__(self):
        self._classes = {}
    def add(self, cls):
        self._classes[cls.__module__, cls.__name__] = cls
        return cls
    def object_hook(self, dct):
        module, cls_name = dct.pop('__type__', (None, None))
        if cls_name is not None:
            return self._classes[module, cls_name].from_dict(dct)
        else:
            return dct
    def default(self, obj):
        dct = obj.to_dict()
        dct['__type__'] = [type(obj).__module__,
                           type(obj).__name__]
        return dct

registry = SerializerRegistry()

@registry.add
class A(object):
    def __init__(self, item1):
        self.item1 = item1
    def __repr__(self):
        return str(self.__dict__)
    def to_dict(self):
        return dict(item1=self.item1)
    @classmethod
    def from_dict(cls, dct):
        return cls(**dct)

s = json.dumps(A(1), default=registry.default)
a = json.loads(s, object_hook=registry.object_hook)

Это приводит к следующему:

>>> s
'{"item1": 1, "__type__": ["__main__", "A"]}'
>>> a
{'item1': 1}

Но на самом деле вам нужна функция default, которая создает словарь из объектов, которые вы хотите сериализовать,и функция object_hook, которая возвращает объект (правильного типа), когда ему дается словарь, если словаря недостаточно.Наилучший подход состоит в том, чтобы иметь в сериализуемых классах методы, которые создают dict из объекта и конструируют его обратно, а также иметь отображение, которое распознает, к какому классу относятся словари.

Вы также можете добавитьидентификатор для классов, которые будут использоваться в качестве индекса для _classes.Таким образом, у вас не будет проблем, если вам придется переместить класс.

3 голосов
/ 28 января 2011

Согласно документу json для модуля (simplejson был принят как json в Python 2.6), вам необходимо расширить класс json.JSONEncoder, переопределяя его метод по умолчанию, чтобы преобразовать ваш объект в тип, который сериализованная. Похоже, не существует метода, который он ищет для вашего объекта.

...