Most compact way to serialize an object that contains other objects in python?


Most compact way to serialize an object that contains other objects in python?



What is the most compact way to serialize an object that contains other objects or even nested collections of other objects in python?



More info:



In my project, I have collections of instances of my own classes, and each some of these classes again contain collections of instances of some of my other classes.



I need to transfer some of these collections through a REST api using json files.



We can use an example like below.



Example Code:


from typing import List, Dict


class Organization:
def __init__(self, name):
self.name = name
self.employees = # type: List[Person]


class Person:
def __init__(self, name: str):
self.name = name
self.qualification = ""
self.pets = # type: List[Pet]


class Pet:
def __init__(self, name: str, species: str):
self.species = species
self.name = name


if __name__ == "__main__":
pets_dict = {"Simba": "cat", "Winnie": "bear", "Tigger": "bear", "Drogon": "dragon",
"Rhaegal": "dragon", "Viserion":"dragon", "Ghost": "wolf"}
people_dict = ["Walt", "Christopher", "Dany", "Jon"]
pets_obj = {p: Pet(p, pets_dict[p]) for p in pets_dict} # type: Dict[str, Pet]
people_obj = {p: Person(p) for p in people_dict} # type: Dict[str, Person]
people_obj["Walt"].pets = [pets_obj["Simba"],]
people_obj["Christopher"].pets = [pets_obj["Winnie"], pets_obj["Tigger"]]
people_obj["Dany"].pets = [pets_obj["Drogon"], pets_obj["Rhaegal"], pets_obj["Viserion"]]
people_obj["Jon"].pets = [pets_obj["Ghost"], ]
organization = Organization("Stories")
organization.employees = list(people_obj.values())

print(vars(organization))



Output:


{'name': 'Stories', 'employees': [<__main__.Person object at 0x00000000025DFDD8>, <__main__.Person object at 0x00000000025E6630>, <__main__.Person object at 0x00000000025E6AC8>, <__main__.Person object at 0x00000000025E6B38>]}



As we can see, only the highest level of the object has been serialized, while the objects inside any of its collection keep their type.



Solutions Found So Far:



There is this question-answer.
It contains 2 suggestions: The first is for simple cases only, by using dumps(organization.__dict__). This does not work in the example case. The second method is to write an encoding class, which is similar to the solution (2) below. It's not a bad solution, but see my "Why I think there should be a better way" below.


dumps(organization.__dict__)



Use json.dump (or dumps) and include a serializer for each custom class.


def my_serializer(obj):
if type(obj) in (Organization, Person, Pet):
return vars(obj)
else:
return obj



then do


print(dumps(organization, default=my_serializer))



Why I think there should be a better way:



Essentially I am looking for a deep vars (like there is a deepcopy). I can imagine that there are many who have wanted such a thing, so I expect a simple and clear solution exists. I just couldn't Google my way to it, so I turn to the community.


vars


deepcopy




1 Answer
1



Option 2 - passing a serialiser to json.dumps - is the right way to do this. You provide the serialiser, json.dumps handles recursing through the object graph.


json.dumps


json.dumps



There's no value in deep_vars unless you want a dictionary of your object graph, but you don't want a dictionary, you just the json.


deep_vars





Thanks! I agree. Just for my education: if I did want a dictionary of my object graph, is there a way to do it?
– levraininjaneer
Jul 3 at 6:23






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

api-platform.com Unable to generate an IRI for the item of type

How to set up datasource with Spring for HikariCP?

Display dokan vendor name on Woocommerce single product pages