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'>
Advertisement
Answer
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.