I am using a nested defaultdict to keep code clean and reduce the redundant code.
I am constructing a dictionary such as:
{"Store1": {"Product1": 1}, "Store2": {"Product1": 2, "Product2": 1}}
I tried to implement the answer to this question Nested dictionary with defaults, which would raise the exception:
AttributeError: 'int' object has no attribute 'items'
from collections import defaultdict, Counter
d = defaultdict(lambda: defaultdict(lambda: Counter()))
d["Store1"]["Product1"] += 1
print(d)
is there anyway I can for example:
d["Store1"]["Product1"] += 1
When you use the following
d = defaultdict(lambda: defaultdict(lambda: Counter()))
d["Store1"]["Product1"] += 1
then, d["Store1"]
will create a new element of "type" defaultdict(lambda: Counter())
and thus d["Store1"]["Product1"]
will create a new element of type Counter
. Hence when you do += 1
, it attempts to augment the Counter
object by 1
. This, however, is not defined, as the types are not compatible:
>>> c = Counter()
>>> c += 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/---/lib/python3.7/collections/__init__.py", line 832, in __iadd__
for elem, count in other.items():
AttributeError: 'int' object has no attribute 'items'
As you can observe, it assumes that the right hand side follows the Mapping
protocol and it attempts to add the r.h.s. counts to its own. I.e. something like:
>>> c = Counter(a=1)
>>> c += Counter(a=2, b=3)
>>> c
Counter({'a': 3, 'b': 3})
When you use defaultdict(lambda: defaultdict(int))
on the other hand, then d["Store1"]["Product1"]
creates a new int
object, which can be incremented by += 1
and written back to the dict.