I have a utility class that makes Python dictionaries behave somewhat like JavaScript objects as far as getting and setting attributes.
class DotDict(dict):
"""
a dictionary that supports dot notation
as well as dictionary access notation
usage: d = DotDict() or d = DotDict({'val1':'first'})
set attributes: d.val2 = 'second' or d['val2'] = 'second'
get attributes: d.val2 or d['val2']
"""
__getattr__ = dict.__getitem__
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
I would like to make it so it also converts nested dictionaries into DotDict() instances. I was hoping to be able to do something like this with __init__
or __new__
, but I haven't come up with anything that works:
def __init__(self, dct):
for key in dct.keys():
if hasattr(dct[key], 'keys'):
dct[key] = DotDict(dct[key])
How can I recursively convert the nested dictionaries into DotDict() instances?
>>> dct = {'scalar_value':1, 'nested_dict':{'value':2}}
>>> dct = DotDict(dct)
>>> print dct
{'scalar_value': 1, 'nested_dict': {'value': 2}}
>>> print type(dct)
<class '__main__.DotDict'>
>>> print type(dct['nested_dict'])
<type 'dict'>
I don't see where you are copying the values in the constructor. Here DotDict is always empty because of that. When I added the key assignment, it worked:
class DotDict(dict):
"""
a dictionary that supports dot notation
as well as dictionary access notation
usage: d = DotDict() or d = DotDict({'val1':'first'})
set attributes: d.val2 = 'second' or d['val2'] = 'second'
get attributes: d.val2 or d['val2']
"""
__getattr__ = dict.__getitem__
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
def __init__(self, dct):
for key, value in dct.items():
if hasattr(value, 'keys'):
value = DotDict(value)
self[key] = value
dct = {'scalar_value':1, 'nested_dict':{'value':2, 'nested_nested': {'x': 21}}}
dct = DotDict(dct)
print dct.nested_dict.nested_nested.x
It looks a bit dangerous and error prone, not to mention source of countless surprises to other developers, but seems to be working.
Shamelessly plugging my own package
There is a package doing exactly what you want and also something more and it is called Prodict.
from prodict import Prodict
life_dict = {'bigBang':
{'stars':
{'planets': []}
}
}
life = Prodict.from_dict(life_dict)
print(life.bigBang.stars.planets)
# prints []
# you can even add new properties dynamically
life.bigBang.galaxies = []
PS 1: I'm the author of the Prodict.
PS 2: This is a direct copy paste of an answer of another question.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With