import json import typing from json import JSONEncoder def _default(self, obj): return getattr(obj.__class__, "serialize", _default.default)(obj) _default.default = JSONEncoder().default JSONEncoder.default = _default class ISerializable: def serialize(self) -> str: d = {k: v for k, v in self.__dict__.items() if not k.startswith("_")} s = json.dumps(d) s = s.replace('"{', '{') s = s.replace('}"', '}') s = s.replace("\\", "") return s @staticmethod def deserialize(tt, json_string: str) -> 'ISerializable': t = tt() json_data = json.loads(json_string) for k, v in json_data.items(): if isinstance(v, dict): ct = type(getattr(t, k)) o = ct.deserialize(ct, json.dumps(v)) setattr(t, k, o) elif isinstance(v, list): tab = ISerializable.deserialize_list(k, t, v) setattr(t, k, tab) else: setattr(t, k, v) return t @staticmethod def deserialize_list(k, t, v): tab = [] for e in v: if isinstance(e, dict): ct = type(getattr(t, k)[0]) o = ct.deserialize(ct, json.dumps(e)) tab.append(o) elif isinstance(e, list): tab.append(ISerializable.deserialize_list(k, t, e)) else: tab.append(e) return tab class TT(ISerializable): def __init__(self): self.count = 2 self.o = OMG() def __str__(self): return f"TT.{self.count},{self.o}" class OMG(ISerializable): def __init__(self): self.count = 20 def __str__(self): return f"OMG.{self.count}" class Test(ISerializable): name: str parent: TT _hidden: int parent: typing.List[TT] def __init__(self): self.name = "toto" self.parent = TT() self.parents = [TT(), TT()] self._hidden = 10 def __str__(self): pt = "" for p in self.parents: pt += str(p) return f"{self.name},{pt},{self.parent},{self._hidden}" def main(): t = Test() print(t) s = t.serialize() print(s) t = Test.deserialize(Test, s) print(t) # Press the green button in the gutter to run the script. if __name__ == '__main__': main()