سؤال

I have a class defined like this

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

when I do:

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

I can't find the reason why.

Do I need to add any particular method to A for simplejson to serialize my class object?

هل كانت مفيدة؟

المحلول

You can't serialize arbitrary objects with simplejson. You need to pass a default and object_hook to dump and load. Here's an example:

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)

This results in this:

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

But what you really need is a function default that creates dictionary from the objects that you wish to serialize, and a function object_hook that returns an object (of the correct type) when it is given a dictionary if a dictionary isn't enough. The best approach is to have methods on the serializable classes that create a dict from the object and that construct it back, and also to have a mapping that recognizes to which class the dictionaries belong.

You can also add an identifier to the classes to be used as an index for _classes. This way you wouldn't have issues if you have to move a class.

نصائح أخرى

According to the json module docs (simplejson was adopted as json in Python 2.6), you need to extend the json.JSONEncoder class, overriding its default method to translate your object into a type that can be serialised. There doesn't appear to be a method that it looks for on your object.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top