Поиск вложенного словаря Python со значениями по умолчанию

>>> d2
{'egg': 3, 'ham': {'grill': 4, 'fry': 6, 'bake': 5}, 'spam': 2}
>>> d2.get('spamx',99)
99
>>> d2.get('ham')['fry']
6

Я хочу получить значение фри внутри ветчины, если нет, получить значение 99 или 88 в качестве 2-го примера. Но как?


person litd    schedule 09.08.2010    source источник


Ответы (4)


d2.get('ham', {}).get('fry', 88)

Я бы, наверное, разбил его на несколько утверждений в реальной жизни.

ham = d2.get('ham', {})
fry = ham.get('fry', 88)
person Oddthinking    schedule 09.08.2010
comment
скорее d2.get('ham', {}).get('fry', 99), нет? (СУХОЙ!) - person mykhal; 09.08.2010
comment
Сделать что-то читабельным != повторять себя. Повторение себя будет означать написание функции для получения жареной ветчины, а затем еще одной функции для получения жареного спама, когда обе функции могут быть написаны как одна функция, которая принимает ветчину/спам в качестве параметра. - person Jesse Dhillon; 09.08.2010
comment
@Jesse, в предыдущей версии было две ссылки на «фрай» и две ссылки на возвращаемое магическое число. Предложение было явным улучшением. - person Oddthinking; 09.08.2010
comment
Я нигде не вижу эту версию. - person Jesse Dhillon; 09.08.2010
comment
@ Джесси, странно. Я тоже. Мне потребовалось около 3 или 4 правок, чтобы сделать это правильно, но SO, кажется, свернул его в 1, заставив меня выглядеть гораздо более решительным, чем я есть. - person Oddthinking; 10.08.2010
comment
@Oddthinking, я думаю, что если правки сгруппированы в течение определенного промежутка времени, они свернуты. - person Jesse Dhillon; 10.08.2010
comment
Примечание. Это прерывается, если d2.get('ham'... возвращает что-то, что не является словарем (если d2['ham'] было 'other' скажем) - person Peter Gibson; 20.10.2014

Чтобы значения get по умолчанию работали правильно, первое значение по умолчанию должно быть словарем, чтобы вы могли правильно связать вызовы .get в случае сбоя первого.

d.get('ham',{}).get('fry',88)

вы также можете использовать попытку, кроме блока

def get_ham_fry()
  try:
    return d['ham']['fry']
  except AttributeError,e:
    return 88
person Michael Anderson    schedule 09.08.2010
comment
Индексация строк вызовет либо KeyError, если ключ не найден, либо TypeError, если элемент не поддерживает индексацию строк. Я думаю, что AttributeError подходит только для вызовов get. - person Peter Gibson; 20.10.2014

Если вам нужно делать это часто, вы можете написать вспомогательную функцию

def get_nested(d, list_of_keys, default):
    for k in list_of_keys:
        if k not in d: 
            return default
        d=d[k]
    return d

print get_nested(d2,['ham','spam'],99)
print get_nested(d2,['ham','grill'],99)
person John La Rooy    schedule 09.08.2010
comment
По ощущениям уменьшает. functools.reduce(lambda d,x: d[x] if x in d else default, ['ham','spam'], d2) - person kennytm; 09.08.2010
comment
@KennyTM, это поднимает TypeError за ['bacon','spam'] - person John La Rooy; 09.08.2010

Вот решение для работы с вложенными словарями:

def get(root, *keys):
    """
    Returns root[k_1][k_2]...[k_n] if all k_1, ..., k_n are valid keys/indices. 
    Returns None otherwise
    """
    if not keys:
        return root
    if keys[0] not in root:
        return None
    if keys[0] in root:
        return get(root[keys[0]], *keys[1:])

Применение:

>>> d = {'a': 1, 'b': {'c': 3}}
>>> get(d, 'b', 'c')
3
>>> get(d. 'key that's not in d')
None
>>> get(d)
{'a': 1, 'b': {'c': 3}}
person Michael    schedule 12.06.2012