Nested classes are not serializable in python when trying JSON dump

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Nested classes are not serializable in python when trying JSON dump



I currently have two classes in Python like these ones


class person:
age=""
name=""
ranking =

def addRanking():
#Do Whatever treatment and add to the ranking dict

class ranking:
semester = ""
position = ""
gpa = ""



I have my list of person as a dictionary called dictP json.dumps() this dictionary but it seems that it doesn't work. Here is my function to dump to JSON


dictP


json.dumps()


def toJson():
jsonfile = open('dict.json', 'w')
print(json.dump(listP, jsonfile))



I get the famous: is not JSON serializable.



Would you know what I can do to help this problem. I thought that having two dictionaries (which are serializable) would avoid this kind of issue, but apparently not.



Thanks in advance



Edit:



Here is an example (typed on my phone sorry for typos, I'm not sure it does run but it's so you get the idea):


class person:
age=""
name=""
ranking =

def __init__(self, age, name):
self.age = age
self.name = name
self.ranking =

def addRanking(self,semester,position,gpa):
#if the semester is not already present in the data for that person
self.ranking[semester] = make_ranking(semester,position,gpa)

class ranking:
semester = ""
position = ""
gpa = ""

def __init__(self, semester, position, gpa):
self.semester = semester
self.position = position
self.gpa = gpa

dictP =


def make_person(age, name):
# Some stuff happens there
return person(age,name)

def make_ranking(semester,postion,gpa):
#some computation there
return ranking(semester,position,gpa)

def pretending_to_read_csv():
age = 12
name = "Alice"
p = make_person(age, name)
dictP["1"] = p

age = 13
name = "Alice"
p = make_person(age, name)
dictP["2"] = p

#We read a csv for ranking that gives us an ID
semester = 1
position = 4
gpa = 3.2
id = 1

dictP["1"].addRanking(semester, position, gpa)

semester = 2
position = 4
gpa = 3.2
id = 1

dictP["1"].addRanking(semester, position, gpa)




2 Answers
2



For a dictionary to be serializable, note that all the keys & values in that dictionary must be serializable as well. You did not show us what listP contains, but I'm guessing it's something like this:


listP


>>> listP
[<__main__.person instance at 0x107b65290>, <__main__.person instance at 0x107b65368>]



Python instances are not serializable.



I think you want a list of dictionaries, which would look like this:


>>> listP
['ranking': , 'age': 10, 'name': 'fred', 'ranking': , 'age': 20, 'name': 'mary']



This would serialize as you expect:


>>> import json
>>> json.dumps(listP)
'["ranking": , "age": 10, "name": "fred", "ranking": , "age": 20, "name": "mary"]'



UPDATE



(Thanks for adding example code.)


>>> pretending_to_read_csv()
>>> dictP
'1': <__main__.person instance at 0x107b65368>, '2': <__main__.person instance at 0x107b863b0>



Recall that user-defined classes cannot be serialized automatically. It's possible to extend the JSONEncoder directly to handle these cases, but all you really need is a function that can turn your object into a dictionary comprised entirely of primitives.


JSONEncoder


def convert_ranking(ranking):
return
"semester": ranking.semester,
"position": ranking.position,
"gpa": ranking.gpa

def convert_person(person):
return
"age": person.age,
"name": person.name,
"ranking": semester: convert_ranking(ranking) for semester, ranking in person.ranking.iteritems()



One more dictionary comprehension to actually do the conversion and you're all set:


>>> new_dict = person_id: convert_person(person) for person_id, person in dictP.iteritems()
>>> from pprint import pprint
>>> pprint(new_dict)
'1': 'age': 12,
'name': 'Alice',
'ranking': 1: 'gpa': 3.2, 'position': 4, 'semester': 1,
2: 'gpa': 3.2, 'position': 4, 'semester': 2,
'2': 'age': 13, 'name': 'Alice', 'ranking':



Since no user-defined objects are stuffed in there, this will serialize as you hope:


>>> json.dumps(new_dict)
'"1": "ranking": "1": "position": 4, "semester": 1, "gpa": 3.2, "2": "position": 4, "semester": 2, "gpa": 3.2, "age": 12, "name": "Alice", "2": "ranking": , "age": 13, "name": "Alice"'





Currently on the phone so it’s hard to look at my code or comment more (or even make sense of everything you said) but my ListP contains an ID and an instance of Perso.
– LBes
Aug 8 at 18:17





Can you add a copy of the listP you're working with to your question?
– chris
Aug 8 at 18:19


listP





well I just build it on the fly while reading a bunch of CSVs but it's basically the key is an ID and the value is an instance of Person
– LBes
Aug 8 at 18:35





Ok, that is the root of your issue: an instance of your person class is not serializable, whether it's the value of a dictionary or an element in a list.
– chris
Aug 8 at 18:41


person





so I have my dictionary with instances of person and then each instance of person got instances of rankings... How should I proceed. This thing is seriously confusing me... Can you edit your answer ?
– LBes
Aug 8 at 20:31



You can try calling json.dump on the .__dict__ member of your instance. You say that you have a list of person instances so try doing something like this:


json.dump


.__dict__


listJSON =
for p in listP
#append the value of the dictionary containing data about your person instance to a list
listJSON.append(p.__dict__)
json.dump(listJSON, jsonfile)



If you are storing your person instances in a dictionary like so: dictP = 'person1': p1, 'person2': p2 this solution will loop through the keys and change their corresponding values to the __dict__ member of the instance:


dictP = 'person1': p1, 'person2': p2


__dict__


for key in dictP:
dictP[key] = dictP[key].__dict__
json.dump(dictP, jsonfile)





I actually have a dictionary of Person. So what would happen then ? Does t change anything to call .__dict__?
– LBes
Aug 8 at 18:08





I've updated my answer @LBes
– Andrew Delgadillo
Aug 8 at 18:17






will try that in a couple of hours. Currently on the phone.
– LBes
Aug 8 at 18:18






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard