I want a function to create a Python object with from a deserialized JSON object (DSO). The function must support recursion. If an item in the DSO is a dictionary, then dynamically create an associated property for each key in the dictionary. If an item is a sequence (list/tuple/set), then create an object that supports indexing, ie. obj[val].
I have the first part of this requirement working fine. I'm not sure what is the most elegant way to approach dealing with sequences and dynamically creating a __getitem__ method on the fly.
Here's my code:
def to_obj(item):
'''Create object from deserialized JSON.
This function calls itself recursively. If item is a {}, then an
object that mirrors the dictionary is returned. Otherwise, just the item
itself is returned.
:param item: <object>.
:returns: <object>.
'''
if isinstance(item, dict):
obj = type('__object', (object,), {})
for key, value in item.items():
setattr(obj, key, to_obj(value))
return obj
else:
return item
This transforms this:
artifact = {
"k1": "value1",
"k2": {
"k2key1": "k2value1",
"k2key2": {
"k2key2key1": "k2key2value1",
}
}
}
into this:
obj = to_obj(artifact)
obj.k2.k2key2.k2key2key1 # returns "k2key2value1"
However, sometimes the value of some of the {} items are sequences, like so:
artifact = {
"k1": "value1",
"k2": {
"k2key1": "k2value1",
"k2key2": [
{
"item0key1": "item0value1",
"item0key2": "item0value2"
},
{
"item1key1": "item1value1",
"item1key2": "item1value2"
}
]
}
}
I want the recursion to work in the same way for sequences that may contain other dictionaries, etc - so I need code that supports the following. Note the element lookup on k2key2.
obj = to_obj(artifact)
obj.k2.k2key2[1].item1key2 # returns "item1value2"
I saw an SO post by @MartijnPieters mentioning the descriptor protocol as an elegant way to approach this, but exactly how to do this correctly I do not know.
Any help would be appreciated!