Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make simplejson serializable class

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?

like image 825
dnuske Avatar asked Jan 27 '11 21:01

dnuske


People also ask

How do you serialize a JSON class?

Use toJSON() Method to make class JSON serializable So we don't need to write custom JSONEncoder. This new toJSON() serializer method will return the JSON representation of the Object. i.e., It will convert custom Python Object to JSON string.

How do you serialize a JSON in Python?

Working With JSON Data in Python The json module exposes two methods for serializing Python objects into JSON format. dump() will write Python data to a file-like object. We use this when we want to serialize our Python data to an external JSON file. dumps() will write Python data to a string in JSON format.

Why is set not JSON serializable?

The Python "TypeError: Object of type set is not JSON serializable" occurs when we try to convert a set object to a JSON string. To solve the error, convert the set to a list before serializing it to JSON, e.g. json. dumps(list(my_set)) . Here is an example of how the error occurs.

What is JSON serializable?

Json namespace provides functionality for serializing to and deserializing from JavaScript Object Notation (JSON). Serialization is the process of converting the state of an object, that is, the values of its properties, into a form that can be stored or transmitted.


2 Answers

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.

like image 180
Rosh Oxymoron Avatar answered Oct 25 '22 09:10

Rosh Oxymoron


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.

like image 32
Thomas K Avatar answered Oct 25 '22 11:10

Thomas K