mmaceachran
mmaceachran

Reputation: 3358

JSON serialize objects in Python in list / diconary

I am very new to Python and I have this rather large and complex data structure that is a list of dictionaries with lists of different objects. When I try and convert this to JSON via json.dumps() I get the standard

TypeError: <...> is not JSON serializable

I did some research, and most of the answers point to a standard way of writing a custom encoder, which is fine, I can do that. However, I would like to be able to send my whole data structure to json.dumps() and not loop through everything, figure out what class it is, and build a json object from scratch.

Is there a way to add an encoder/decoder functions to the python class itself, so when I send a complex data structure to json.dumps, the class itself knows what to do.

is there some magic to_json or some way of adding a custom decoder to that class that gets called when the json.dumps runs into it?

Upvotes: 0

Views: 372

Answers (2)

olivierhsta
olivierhsta

Reputation: 103

As Steven Wolfe stated in this thread, you may want to look into jsonpickle. This library allows for encoding and decoding of complex Python object.

You could use it this way:

import jsonpickle

f = open(filename, 'w')
encoded_string = jsonpickle.encode(obj)
f.write(encoded_string)
f.close()

And to retrieve the data as Python object, simply use the jsonpickle.decode(encoded_string) method. As the documentation says :

The new object has the same type and data, but essentially is now a copy of the original.

I think that could work well for you.

Upvotes: 1

wmorrell
wmorrell

Reputation: 5337

The custom encoder class handles that for you when you use json.dumps(my_object, cls=MyCustomJsonEncoder). Your custom encoder would override the default method, which takes self and the object o to encode; test for the different types that need custom serialization, and pass the rest to the default with super(MyCustomJsonEncoder, self).default(o).

A simple example that I often use is as follows:

class JSONEncoder(json.JSONEncoder):
    """
    Enhancement of base JSONEncoder, also handling these objects:
     * datetime.datetime
     * decimal.Decimal
     * uuid.UUID
    """

    def default(self, o):
        if isinstance(o, Decimal):
            return float(o)
        elif isinstance(o, UUID):
            return str(o)
        elif isinstance(o, datetime):
            return {
                '__type__': 'datetime',
                '__value__': o.isoformat(),
            }
        return super(JSONEncoder, self).default(o)

    @staticmethod
    def dumps(obj):
        return json.dumps(obj, cls=JSONEncoder)

Upvotes: 1

Related Questions