Thanks to some great folks on SO, I discovered the possibilities offered by collections.defaultdict
, notably in readability and speed. I have put them to use with success.
Now I would like to implement three levels of dictionaries, the two top ones being defaultdict
and the lowest one being int
. I don't find the appropriate way to do this. Here is my attempt:
from collections import defaultdict
d = defaultdict(defaultdict)
a = [("key1", {"a1":22, "a2":33}),
("key2", {"a1":32, "a2":55}),
("key3", {"a1":43, "a2":44})]
for i in a:
d[i[0]] = i[1]
Now this works, but the following, which is the desired behavior, doesn't:
d["key4"]["a1"] + 1
I suspect that I should have declared somewhere that the second level defaultdict
is of type int
, but I didn't find where or how to do so.
The reason I am using defaultdict
in the first place is to avoid having to initialize the dictionary for each new key.
Any more elegant suggestion?
Thanks pythoneers!
Use:
This will create a new
defaultdict(int)
whenever a new key is accessed ind
.Look at nosklo's answer here for a more general solution.
As per @rschwieb's request for
D['key'] += 1
, we can expand on previous by overriding addition by defining__add__
method, to make this behave more like acollections.Counter()
First
__missing__
will be called to create a new empty value, which will be passed into__add__
. We test the value, counting on empty values to beFalse
.See emulating numeric types for more information on overriding.
Examples:
Rather than checking argument is a Number (very non-python, amirite!) we could just provide a default 0 value and then attempt the operation:
Late to the party, but for arbitrary depth I just found myself doing something like this:
The trick here is basically to make the
DeepDict
instance itself a valid factory for constructing missing values. Now we can do things likeAnother way to make a pickleable, nested defaultdict is to use a partial object instead of a lambda:
This will work because the defaultdict class is globally accessible at the module level: