I'd like to achieve the following:
foodict['foo.bar.baz'] = 'foo'
{
'foo': {
'bar': {
'baz': 'foo'
}
}
}
}
...creating keys recursively.
After scratching my head for a while, I've come up with this:
class Config(dict):
def __init__(self, *args, **kwargs):
self.super = super(Config, self)
self.update(*args, **kwargs)
def __setitem__(self, keys, value):
keys = keys.split('.')
keys.reverse()
config = Config()
for i, k in enumerate(keys):
if i == 0:
config = Config(**{ k: value })
else:
config = Config(**{ k: config })
self.super.update(config)
You might consider the "infinite defaultdict" recipe, from Raymond Hettinger himself:
https://twitter.com/raymondh/status/343823801278140417
>>> from collections import defaultdict
>>> infinite_defaultdict = lambda: defaultdict(infinite_defaultdict)
>>> d = infinite_defaultdict()
>>> d['foo']['bar']['baz'] = 'foo'
>>> d
defaultdict(<function <lambda> at 0x1040388c8>, {'foo': defaultdict(<function <lambda> at 0x1040388c8>, {'bar': defaultdict(<function <lambda> at 0x1040388c8>, {'baz': 'foo'})})})
Another option is to implement __missing__
:
>>> class InfiniteDict(dict):
... def __missing__(self, val):
... d = InfiniteDict()
... self[val] = d
... return d
...
>>> d = InfiniteDict()
>>> d['foo']['bar']['baz'] = 'foo'
>>> d
{'foo': {'bar': {'baz': 'foo'}}}
And if you must have attribute access:
class InfiniteDict(dict):
def __missing__(self, val):
d = InfiniteDict()
self[val] = d
return d
def __getattr__(self, item):
return self.__getitem__(item)
def __setattr__(self, item, value):
super().__setitem__(item, value)
In action:
>>> d = InfiniteDict()
>>> d.foo.bar.baz = 'foo'
>>> d
{'foo': {'bar': {'baz': 'foo'}}}
>>>
Although, that's a little quick-and-dirty, so no guarantees there aren't any bugs. And there are very little guards against, for example, collisions with actual attributes:
>>> d.keys = 'should I be allowed?'
>>> d
{'foo': {'bar': {'baz': 'foo'}}, 'keys': 'should I be allowed?'}
>>> d.keys()
dict_keys(['foo', 'keys'])
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