# Python arbitrary objects Serialization and Deserialization [closed]

I am trying to convert objects inside an object(arbitrary objects) to Json and later retrieve it. I have developed some codes and would like to share if there is any problem in the code.

import json


Here is the first class

class Foo():
def __init__(self,x,y,bar):
self.x =x
self.y = y
self.bar = bar #Second class object is here

def toJson(self):
return json.dumps(Foo(self.x,self.y,self.bar).__dict__)

@staticmethod
def fromJson(jsonData):
return Foo(
x = data['x'],
y = data['y'],
bar = Bar.fromJson(data['bar'])
)


Here is the second class

class Bar():
def __init__(self, z):
self.z = z

def toJson(self):
return json.dumps(Bar(self.z).__dict__)

@staticmethod
def fromJson(jsonData):
return Bar(
z = data['z'],
)


Convert to Json

jsonData = Foo(100,500,Bar(900).toJson()).toJson()


Retrieve the Json and convert to Object

foo = Foo.fromJson(jsonData)


Print the Object attributes

print(foo.bar.z)


It works actually. But is there any memory leakage? Any security issue?

• What's the matter with your class naming? – Mast Jul 6 at 6:52
• Is this how your actual code looks? Please take a look at the help center and note we need to see the real deal. Obfuscated code is not reviewable. – Mast Jul 6 at 6:53
• Yes, why not. This is the concept foo is an object which has another object bar. My question is only that is this right way to serialize and deserialize Python objects. – Yunus Jul 6 at 6:58

This is not a good interface to serialize to JSON:

jsonData = Foo(100,500,Bar(900).toJson()).toJson()


You would want it to be transparent and be able to do

foo = Foo(100, 500, Bar(900))
json_data = foo.to_json()


Otherwise you have weird things, like you are initializing Foo with the serialized Bar object, instead of the actual object, just so you can serialize it. This will fail as soon as your initializer does anything (except setting properties) with the arguments it is passed.

I would consider implementing a custom JSON Encode/Decoder:

class Foo:
def __init__(self, x, y, bar):
self.x =x
self.y = y
self.bar = bar #Second class object is here

class Bar:
def __init__(self, z):
self.z = z

import json

class ClassJSONEncoder(json.JSONEncoder):
def default(self, obj):
if hasattr(obj, "__dict__"):
return {"__class__": obj.__class__.__name__, **obj.__dict__}
# Let the base class default method raise the TypeError
return json.JSONEncoder.default(self, obj)

def as_class(dct):
if '__class__' in dct:
cls_name = dct.pop("__class__")
cls = vars()[cls_name]
return cls(**dct)
return dct


Now, if you want to, you can add a JSONSerializable mix-in:

class JSONSerializable:
def to_json(self):
return json.dumps(self, cls=ClassJSONEncoder)

@classmethod
def from_json(cls, s):
assert isinstance(self, cls)
return self


So you can directly inherit from this:

class Foo(JSONSerializable):
...

class Bar(JSONSerializable):
...

Foo(100, 200, Bar(900)).to_json()
# '{"__class__": "Foo", "x": 100, "y": 200, "bar": {"__class__": "Bar", "z": 900}}'
Foo.from_json(Foo(100, 200, Bar(900)).to_json())
# <__main__.Foo at 0x7effb1d86e48>
# with {'x': 100, 'y': 200, 'bar': {'z': 900}}


Although this is maybe still not the best implementation, because Foo.from_json suggests that you get back a Foo object, while this serialization relies on the correct "__class__" key for the class name (although I added a check that this is the case).

This also does not deal with positional-only arguments. It also requires, just like your code, the __dict__ to be necessary and sufficient for creating a new object.

However, this approach has the added advantage that it can override the to_json and from_json methods, should you need to, while covering the base cases quite nicely, IMO.

• I was looking for something like this. Thanks for this broad answer. – Yunus Jul 7 at 4:43

There's a library for this dataclasses-json. Whilst it's a pretty poor library the internal code is bad, there's few tests, the documentation is quite small and the design is starting to suffer from these poor decisions. It works, and for your code it is good enough.

You should be able to see that all serialization and deserialization is performed automatically. This is good as then you can focus on using the objects rather than converting to and from them.

from __future__ import annotations

from dataclasses import dataclass

from dataclasses_json import dataclass_json

@dataclass_json
@dataclass
class Foo:
x: int
y: int
bar: Bar

@dataclass_json
@dataclass
class Bar:
z: int

raw = '{"x": 100, "y": 500, "bar": {"z": 900}}'
obj = Foo.from_json(raw)
assert obj == Foo(100, 500, Bar(900))
assert obj.to_json() == raw

• Thanks for this information. So if you could reply me with yes/no, I can go with my code implementation, right? As I am not going to implement any library which might have poor documentation and I may fall in trouble. – Yunus Jul 6 at 9:49
• @Yunus Your comment does not make sense to me. – user226435 Jul 6 at 9:50