user3497492
user3497492

Reputation: 275

JSON serialization of dictionary with complex objects

I am trying to serialize the dictionary playersElo for saving/loading it as/from JSON.

But as it's not a serializable object and I can't find a way to do it.

playersElo={} # dictionary of {<int> : <PlayerElo>}
playersElo[1] = PlayerElo()
playersElo[2] = PlayerElo()
...

class PlayerElo:
    """
    A class to represent a player in the Elo Rating System
    """
    def __init__(self, name: str, id: str, rating):
        self.id = id
        self.name = name
        # comment the 2 lines below in order to start with a rating associated
        # to current player rank
        self.eloratings = {0: 1500}
        self.elomatches = {0: 0}
        self.initialrating = rating

Upvotes: 0

Views: 1440

Answers (2)

Tim Roberts
Tim Roberts

Reputation: 54698

Maybe this can be a starting spot for you. The serializer grabs the __dict__ attribute from the object and makes a new dict-of-dicts, then writes it to JSON. The deserializer creates a dummy object, then updates the __dict__ on the way in.

import json

class PlayerElo:
    """
    A class to represent a player in the Elo Rating System
    """
    def __init__(self, name: str, id: str, rating):
        self.id = id
        self.name = name
        self.eloratings = {0: 1500}
        self.elomatches = {0: 0}
        self.initialrating = rating


playersElo={} # dictionary of {<int> : <PlayerElo>}
playersElo[1] = PlayerElo('Joe','123',999)
playersElo[2] = PlayerElo('Bill','456',1999)

def serialize(ratings):
    newdict = {i:j.__dict__ for i,j in ratings.items()}
    json.dump( newdict, open('x.json','w') )

def deserialize():
    o = json.load(open('x.json'))
    pe = {}
    for k,v in o.items():
        obj = PlayerElo('0','0',0)
        obj.__dict__.update( v )
        pe[int(k)] = obj
    return pe

print(playersElo)
serialize( playersElo )
pe = deserialize( )
print(pe)

Upvotes: 2

martineau
martineau

Reputation: 123443

You can extend the json.JSONEncoder to handle instances of your class. There are examples in the module's documentation, but here one why of doing it with your PlayerElo class.

Note: Also see my answer to the question Making object JSON serializable with regular encoder for a more generic way of doing it.

import json


class PlayerElo:
    """ A class to represent a player in the Elo Rating System. """

    def __init__(self, name: str, id: str, rating):
        self.id = id
        self.name = name
        # comment the 2 lines below in order to start with a rating associated
        # to current player rank
        self.eloratings = {0: 1500}
        self.elomatches = {0: 0}
        self.initialrating = rating


class MyJSONEcoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, PlayerElo):
            return dict(type='PlayerElo', name=obj.name, id = obj.id,
                        rating=obj.initialrating)
        return super().default(obj)


playersElo={} # dictionary of {<int> : <PlayerElo>}
playersElo[1] = PlayerElo('Bob', 'thx1138', 4)
playersElo[2] = PlayerElo('Sue', 'p-138', 3)

from pprint import pprint
my_encoder = MyJSONEcoder()
pprint(my_encoder.encode(playersElo))

Here the JSON string it generated and printed:

('{"1": {"type": "PlayerElo", "name": "Bob", "id": "thx1138", "rating": 4}, '
 '"2": {"type": "PlayerElo", "name": "Sue", "id": "p-138", "rating": 3}}')

Upvotes: 1

Related Questions