json serialization of a list of objects of a custom class

Question:

I have a song class, which holds the attributes to a song, and it is a custom class. I also have a list of songs in a list called track list. When I try to json.dump the list, I get an error that says :

TypeError: Object of type 'Song' is not JSON serializable

How would I go about converting this list of songs to json?

Here is the additional relevant code that returns the error:

class Song:
def __init__(self, sname, sartist, coverart, albname, albartist, spotid):
    self.sname = sname
    self.sartist = sartist
    self.coverart = coverart
    self.albname = albname
    self.albartist = albartist
    self.spotid = spotid

tracklist = createDict(tracks) ##creates the list of songs, works fine
jsontracks = json.dumps(tracklist)
pp.pprint(jsontracks)

Thanks

Asked By: Anish Laddha

||

Answers:

I’ve solved this by adding an encode() method to the class:

def encode(self):
    return self.__dict__

and adding some arguments to json.dumps:

jsontracks = json.dumps(tracklist, default=lambda o: o.encode(), indent=4)

This will "crawl" down your class tree (if you have any child classes) and encode every object as a json list/object automatically. This should work with just about any class and is fast to type. You may also want to control which class parameters get encoded with something like:

def encode(self):
    return {'name': self.name,
            'code': self.code,
            'amount': self.amount,
            'minimum': self.minimum,
            'maximum': self.maximum}

or a little bit faster to edit (if you’re lazy like me):

def encode(self):
    encoded_items = ['name', 'code', 'batch_size', 'cost',
                     'unit', 'ingredients', 'nutrients']
    return {k: v for k, v in self.__dict__.items() if k in encoded_items}

full code:

import json


class Song:
    def __init__(self, sname, sartist, coverart, albname, albartist, spotid):
        self.sname = sname
        self.sartist = sartist
        self.coverart = coverart
        self.albname = albname
        self.albartist = albartist
        self.spotid = spotid

    def encode(self):
        return self.__dict__


tracklist = [
    Song('Imagine', 'John Lennon', None, None, None, None),
    Song('Hey Jude', 'The Beatles', None, None, None, None),
    Song('(I Can't Get No) Satisfaction', 'The Rolling Stones', None, None, None, None),
]

jsontracks = json.dumps(tracklist, default=lambda o: o.encode(), indent=4)
print(jsontracks)

output:

[
    {
        "sname": "Imagine",
        "sartist": "John Lennon",
        "coverart": null,
        "albname": null,
        "albartist": null,
        "spotid": null
    },
    {
        "sname": "Hey Jude",
        "sartist": "The Beatles",
        "coverart": null,
        "albname": null,
        "albartist": null,
        "spotid": null
    },
    {
        "sname": "(I Can't Get No) Satisfaction",
        "sartist": "The Rolling Stones",
        "coverart": null,
        "albname": null,
        "albartist": null,
        "spotid": null
    }
]
Answered By: bherbruck