I had the same need, so I created the Prodict.
For your case, you can do it in one line:
mydict = {
'first': {
'second': {
'third': {
'fourth': 'the end'
}
}
}
}
dotdict = Prodict.from_dict(mydict)
print(dotdict.first.second.third.fourth) # "the end"
After that, use dotdict just like a dict, because it is a subclass of dict:
dotdict.first == dotdict['first'] # True
You can also add more keys dynamically with dot notation:
dotdict.new_key = 'hooray'
print(dotdict.new_key) # "hooray"
It works even if the new keys are nested dictionaries:
dotdict.it = {'just': 'works'}
print(dotdict.it.just) # "works"
Lastly, if you define your keys beforehand, you get auto completion and auto type conversion:
class User(Prodict):
user_id: int
name: str
user = User(user_id="1", "name":"Ramazan")
type(user.user_id) # <class 'int'>
# IDE will be able to auto complete 'user_id' and 'name' properties
UPDATE:
This is the test result for the same code written by @kabanus:
x = {'a': {'b': {'c': {'d': 1}}}}
y = dictDotter(x)
z = dct_to_dotdct(x)
w = dictObjecter(x)
p = Prodict.from_dict(x)
print('{:15} : {}'.format('dict dotter', timeit('y.a.b.c.d', globals=locals(), number=10000)))
print('{:15} : {}'.format('prodict', timeit('p.a.b.c.d', globals=locals(), number=10000)))
print('{:15} : {}'.format('dot dict', timeit('z.a.b.c.d', globals=locals(), number=10000)))
print('{:15} : {}'.format('dict objecter', timeit('w.a.b.c.d', globals=locals(), number=10000)))
print('{:15} : {}'.format('original', timeit("get_entry(x,'a.b.c.d')", globals=locals(), number=10000)))
print('{:15} : {:.20f}'.format('prodict getitem', timeit("p['a']['b']['c']['d']", globals=locals(), number=10000)))
print('{:15} : {:.20f}'.format('best ref', timeit("x['a']['b']['c']['d']", globals=locals(), number=10000)))
And results:
dict dotter : 0.04535976458466595
prodict : 0.02860781018446784
dot dict : 0.019078164088831673
dict objecter : 0.0017378700050722368
original : 0.006594238310349346
prodict getitem : 0.00510931794975705289
best ref : 0.00121740293554022105
As you can see, its performance is between "dict dotter" and "dot dict".
Any performance enhancement suggestion will be appreciated.