Why is reduce()
is not working with a defaultdict
object in the following case:
>>> from collections import defaultdict
>>> d = defaultdict(lambda: defaultdict(int))
>>> reduce(dict.get, [1,2], d)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor 'get' requires a 'dict' object but received a 'NoneType'
The above reduce
is equivalent to d[1][2]
, so I expected 0
, i.e. the default return value as output but I got a NoneType
exception instead.
If I use d[1][2]
it works fine as shown below:
>>> d[1][2]
0
Am I doing anything wrong?
dict.get()
returns None
if a key is not present, even for a defaultdict
object.
That's because the job of dict.get()
is to return a default value instead when a key is missing. If it didn't you'd never be able to return a different default (the second argument to dict.get()
):
>>> from collections import defaultdict
>>> d = defaultdict(lambda: defaultdict(int))
>>> d.get(1, 'default')
'default'
In other words, your reduce(dict.get, ..)
function is not the equivalent of the d[1][2]
expression. It is the equivalent of d.get(1).get(2)
, which fails the exact same way:
>>> d = defaultdict(lambda: defaultdict(int))
>>> d.get(1).get(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'get'
Use dict.__getitem__
instead if you want to rely on the auto-insertion behaviour:
>>> reduce(dict.__getitem__, [1,2], d)
0
The expression d[1]
translates directly to d.__getitem__(1)
.