Python parse nested classes from JSON

Viewed 186

I can't find a proper solution to build an object with the nested classes from the parsed json. I would like to keep current init-methods (without the def __init__(self, **entries) -> self.__dict__.update(entries)) together with the __dict__ in the objects (example with the namedtuple does not work for me).
Example of the structure:

class C(object):
    def __init__(self, name: str):
        self.name = name


class B(object):
    def __init__(self, name: str, c: Dict[str, C]):
        self.name = name
        self.c = c


class A(object):
    def __init__(self, name: str, b: List[B]):
        self.name = name
        self.b = b

So I'm receiving an object data 'A' as json:

dump = json.dumps(data, default=lambda o: o.__dict__)
object_a = A(**json.loads(r))

Then if I check the types:

print(type(object_a))
print(type(object_a.b))
print(type(object_a.b[0]))

<class 'A'> <- ok
<class 'list'> <- ok
<class 'dict'> <- expected type 'B'

There is dict instead of the inner object B.
As far as I can see this question is not new. Isn't there a proper and simple way to obtain an object that you need?

1 Answers

Thanks a lot to @AKX for the idea with the serializers.
I've tried to use the marshmallow and it looks pretty good:

from marshmallow import Schema, fields, post_load

class B(object):
    def __init__(self, name: str):
        self.name = name

class BSchema(Schema):
    name = fields.Str()

    @post_load
    def make_b(self, data, **kwargs):
        return B(**data)

class ASchema(Schema):
    name = fields.Str()
    b = fields.List(fields.Nested(BSchema()))

    @post_load
    def make_a(self, data, **kwargs):
        return A(**data)

class A(object):
    def __init__(self, name: str, b: List[B]):
        self.name = name
        self.b = b

When the schemes are ready it becomes simple to serialize/deserialize:

b = B('bbb')
a = A('aaa', [b])
schema = ASchema()
dump = schema.dump(a) # {'name': 'aaa', 'b': [{'name': 'bbb'}]}

a_load = schema.load(dump)
print(type(a_load))       # <class '__main__.A'>
print(type(a_load.b))     # <class 'list'>
print(type(a_load.b[0]))  # <class '__main__.B'>
Related