1

When writing APIs I often need to initialize classes from nested JSONs like this

# When my API receives such a ...
n_json = {"nested1": {"nested2" : { "nested3" : "..." }}}

# .. I need to instantiate a proper object out of it ...
nested1 = Nested1.from_json(json.loads(n_json))

# ... so I can later use the instance in OOP style.
nested1.nested2.run_an_intance_method()

In my code this results in cascades of

class Nested1:
    @classmethod
    def from_json(json):
        self.nested2=Nested2.from_json(json.nested2)

With every layer of nesting this gets more repetetive and error prone. Any clever way to do this?

2
  • show a real example. Don't understand, what you are trying. Commented Aug 25, 2016 at 18:00
  • @Daniel Clearer? Still trying to find the right balance. In this post I explained my motivation for this question --- but obviously too lengthy/opinionated ;) Commented Aug 25, 2016 at 19:10

1 Answer 1

1

This is how you can create a nested object from JSON (similarly to how PHP does that). To create object tree from JSON (rather, parsed JSON, which is just a Python structure), write the following class:

class Nested:
    def __new__(cls, structure):
        self = super(Nested, cls).__new__(cls)
        if type(structure) is dict:
            self.__dict__ = {key: Nested(structure[key]) for key in structure}
        elif type(structure) is list:
            self = [Nested(item) for item in structure]
        else:
            self = structure
        return self

and call it from your parsed JSON. For example:

import json

s = json.dumps({'a': 1, 'b': {'c': [1, 2, {'d': 3}], 'e': {'f': 'g'}}})

result = Nested(json.loads(s))

print(result.a)  #  1

print(result.b.c) # [1, 2, <__main__.Nested object at 0x00000297A983D828>]

print(result.b.c[0]) # 1

print(result.b.c[2].d) # 3

Here is what is how the class works:

  1. __new__ is invoked before anything else. Here we construct an instance of an object (empty)

  2. If new is list, we replace self with list of nested objects, so that Nested({'a': [1, 2, 3]).a is equal to [Nested(1), Nested(2), Nested(3)] (which also equals to just [1, 2, 3], see number 4)

  3. If new is dict, for each key we create a property with the same name and assign Nested(dict[key]) to it.

  4. If any other type, just assign value to self (replace self with value) so that Nested({'a': ['b', 'c', 'd']}).a[0] equals 'b', not Nested(..)

Sign up to request clarification or add additional context in comments.

4 Comments

Thx, looks already nicer than my code which does similar things :) I just enhanced the question to emphasise that Nested1 and Nested2 are different classes, possibly with instance methods and such. Any ideas how one could incorporate that? (Or one should not try this...)
@IwanLD You really should not, at this point you are trying to so something very hacky. If you need to store nested different classes using JSON, you just have to define to_json and from_json on each on them
Yes, I also feel it might be too higher ordery. However using `'self.__dict__' might be viewed this way. As always: It depends. In current situation: I want to generate a nested object oriented DSL from JSON. Guess I don' have much choices but going full functional ;) But it made me think: most classes in my APIs are just nested Datastructures + methods. Why not reduce the datastructure boilerplate to only the essential part - the signature?
This is excellent. What would the process be to export back to JSON?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.