Как вы можете вернуть значение по умолчанию вместо ключевой ошибки при доступе к многомерному словарю в python?

#python #python-2.7 #python-3.x

#python #python-2.7 #python-3.x

Вопрос:

Я пытаюсь получить значение из многомерного словаря, который выглядит, например, так:

 count = {'animals': {'dogs': {'chihuahua': 23}}
  

Итак, если я хочу знать, сколько у меня чихуахуа, я печатаю count['animals']['dogs']['chihuahua']

Но я тоже хочу получить доступ count['vehicles']['cars']['vw golf'] , и вместо ключевых ошибок я хочу вернуть 0.

на самом деле я делаю это:

 if not 'vehicles' in count:
    count['vehicles'] = {}
if not 'cars' in count['vehicles']:
    count['vehicles']['cars'] = {}
if not 'vw golf' in count['vehicles']['cars']['vw golf']:
    count['vehicles']['cars']['vw golf'] = 0
  

Как я могу сделать это лучше?

Я думаю о каком-то типе класса, который наследуется от dict , но это всего лишь идея.

Комментарии:

1. defaultdict s.

Ответ №1:

Вы можете просто сделать:

 return count.get('vehicles', {}).get('cars', {}).get('vw golf', 0)
  

в принципе, верните пустой словарь, если он не найден, и получите счетчик в конце.

Это будет работать при условии, что набор данных находится только в указанном формате. Это не приведет к возникновению ошибок, однако вам может потребоваться настроить его для других типов данных

ДЕМОНСТРАЦИЯ

 >>> count = {'animals': {'dogs': {'chihuahua': 23}}}
>>> count.get('vehicles', {}).get('cars', {}).get('vw golf', 0)
0
>>> count = {'vehicles': {'cars': {'vw golf': 100}}}
>>> count.get('vehicles', {}).get('cars', {}).get('vw golf', 0)
100
>>> 
  

Комментарии:

1. Просто потрясающе, никогда не думал, что это будет так просто.

2. Я никогда не сомневался 🙂

3. Итак, как бы вы добавили bikes vehicles категорию в произвольной точке программы, не выполняя явную проверку count['vehicles'] , существует ли?

4. Вопрос был о получении значений, и я явно упомянул, что это должно быть изменено для других случаев использования. @LukasGraf

Ответ №2:

Используйте комбинацию collections.defaultdict и collections.Counter :

 from collections import Counter
from collections import defaultdict

counts = defaultdict(lambda: defaultdict(Counter))
  

Использование:

 >>> counts['animals']['dogs']['chihuahua'] = 23
>>> counts['vehicles']['cars']['vw golf'] = 100
>>>
>>> counts['animals']['dogs']['chihuahua']
23
>>> # No fancy cars yet, Counter defaults to 0
... counts['vehicles']['cars']['porsche']
0
>>>
>>> # No bikes yet, empty counter
... counts['vehicles']['bikes']
Counter()
  

lambda В построении defaultdict необходимо, потому defaultdict что ожидается фабрика. Таким lambda: defaultdict(Counter) образом, в основном создается функция, которая будет возвращаться defaultdict(Counter) при вызове — это то, что требуется для создания описанного вами многомерного словаря:

Словарь, значения которого по умолчанию соответствуют словарю, значения которого по умолчанию соответствуют экземпляру Counter .

Преимущество этого решения в том, что вам не нужно отслеживать, какие категории вы уже определили. Вы можете просто назначить две новые категории и новое количество за один раз и использовать тот же синтаксис для добавления нового количества для существующих категорий:

 >>> counts['food']['fruit']['bananas'] = 42
>>> counts['food']['fruit']['apples'] = 3
  

(Это предполагает, что вам всегда нужно ровно три измерения для вашей структуры данных, первые два из которых являются словарями категорий, а третье Counter — где будет храниться фактическое количество вещей).