2015-09-18 1 views
1

Почему reduce() не работает с defaultdict объекта в следующем случае:сокращение не работает для collections.defaultdict?

>>> 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' 

выше reduce эквивалентно d[1][2], поэтому я ожидал 0, то есть значение возврата по умолчанию в качестве выхода, но я получил NoneType исключение вместо.

Если я использую d[1][2] он работает отлично, как показано ниже:

>>> d[1][2] 
0 

ли я делаю что-то неправильно?

ответ

4

dict.get() возвращает None если ключ нет, даже для defaultdict объекта.

Это потому, что задание из dict.get() должно возвращать значение по умолчанию вместо того, когда отсутствует ключ. Если это не так, вы никогда не сможете вернуть другую по умолчанию (второй аргумент dict.get()):

>>> from collections import defaultdict 
>>> d = defaultdict(lambda: defaultdict(int)) 
>>> d.get(1, 'default') 
'default' 

Другими словами, ваша reduce(dict.get, ..) функция не эквивалент выражения d[1][2] , Это эквивалент d.get(1).get(2), который не может точно так же:

>>> 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' 

Используйте dict.__getitem__ вместо этого, если вы хотите, чтобы полагаться на поведение авто-вставки:

>>> reduce(dict.__getitem__, [1,2], d) 
0 

Выражение d[1] переводится непосредственно d.__getitem__(1) ,

+0

Почему правильно использовать dict .__ getitem__, а не defaultdict .__ getitem__? – Hammerite

+0

@Hammerite: вы можете использовать либо; 'defaultdict' является подклассом' dict'. –

+0

Отлично! благодаря –

 Смежные вопросы

  • Нет связанных вопросов^_^