Вернуть None, если ключ словаря недоступен

490

Мне нужен способ получить значение словаря, если его ключ существует, или просто вернуть None, если его нет.

Тем не менее, Python вызывает KeyErrorисключение, если вы ищете ключ, который не существует. Я знаю, что могу проверить ключ, но я ищу что-то более явное. Есть ли способ просто вернуть, Noneесли ключ не существует?

Спирос
источник
74
Просто используйте .get(key)вместо[key]
Гейб
12
Диктовка вызывает исключение KeyError. Он не «возвращает key_error».
Бер
3
Доступ к ключу и отлов исключения - это нормально в Python. Это даже хорошо известный и часто используемый шаблон дизайна. Если вместо этого вы возвращаете None, становится невозможным сохранить None в качестве значения, что может иметь значение в некоторых случаях.
Бер
1
Иногда вы хотите, чтобы записи «None» в словаре и пропущенные записи были одинаковыми, в этом случае принятый ответ, кажется, отлично справляется со своей задачей.
Cib
@ Я отредактировал вопрос, чтобы уточнить. Вы могли бы сделать это также.
törzsmókus

Ответы:

814

Ты можешь использовать dict.get()

value = d.get(key)

который вернется, Noneесли key is not in d. Вы также можете указать другое значение по умолчанию, которое будет возвращено вместо None:

value = d.get(key, "empty")
Тим Питцкер
источник
47
Обратите внимание, что второй вариант с запасным вариантом по умолчанию все равно вернется, Noneесли ключ явно указан Noneв dict. Если это не то, что вы хотите, вы можете использовать что-то вроде d.get(key) or "empty".
Cib
15
@cib: Хороший вопрос, но решение имеет аналогичную проблему - если ключ отображается в любой «falsy» значение (например [], "", False, 0.0или на самом деле None), то ваше решение будет всегда возвращаться 0. Если вы ожидаете Nones в качестве значений, вам придется выполнить if key in d:проверку явно.
Тим Пицкер
1
@Cib приветствует это, я не мог понять, что я делаю здесь неправильно.
wobbily_col
@TimPietzcker - не могли бы вы объяснить свой ответ? d.get (ключ) или «пустой» в случае сопоставления ключа с любыми «ложными» значениями - «пустой», если я не ошибаюсь.
MiloMinderbinder,
@MiloMinderbinder: "empty"возвращается, если неверный keyключ d. Это не имеет ничего общего со значением, на keyкоторое отображается.
Тим Пицкер
63

Не удивляйся больше. Это встроено в язык.

    >>> помощь

    Справка по классу dict во встроенных модулях:

    класс dict (объект)
     | dict () -> новый пустой словарь
     | dict (mapping) -> новый словарь, инициализированный из объекта отображения
     | пары (ключ, значение)
    ...
     |  
     | получить(...)
     | D.get (k [, d]) -> D [k], если k в D, иначе d. d по умолчанию Нет.
     |  
    ...
Джон Ла Рой
источник
22

использование dict.get

Возвращает значение для ключа, если ключ находится в словаре, иначе по умолчанию. Если default не задано, по умолчанию используется None, поэтому этот метод никогда не вызывает KeyError.

Daenyth
источник
19

Вы должны использовать get()метод из dictкласса

d = {}
r = d.get('missing_key', None)

Это приведет r == None. Если ключ не найден в словаре, функция get возвращает второй аргумент.

dusktreader
источник
19
Вам не нужно проходить Noneявно. Это по умолчанию.
Бьорн Поллекс
18

Если вы хотите более прозрачное решение, вы можете создать подкласс dictдля такого поведения:

class NoneDict(dict):
    def __getitem__(self, key):
        return dict.get(self, key)

>>> foo = NoneDict([(1,"asdf"), (2,"qwerty")])
>>> foo[1]
'asdf'
>>> foo[2]
'qwerty'
>>> foo[3] is None
True
Бьёрн Поллекс
источник
2
@marineau: Как я уже упоминал в комментарии к другому ответу, проблема в defaultdictтом, что он будет расти каждый раз, когда запрашивается элемент, которого еще нет. Это не всегда желательно.
Бьорн Поллекс
@ BjörnPollex Это, безусловно, элегантный. Есть какие-нибудь подсказки, как расширить это, чтобы поддержать любую глубину? Я имею в виду заставить foo['bar']['test']['sss']возвращаться Noneвместо исключения, после одной глубины он начинает давать TypeErrorвместоKeyError
Нехем
@itsneo. Вы могли бы построить всю структуру NoneDicts. Это поможет в случае, если KeyErrorэто произойдет в самом внутреннем объекте. В противном случае проблема в том, что когда вы возвращаете Noneобъект, вы больше не можете подписаться на него. Одним из уродливых хаков было бы возвращение другого объекта, который вроде бы тестирует None. Остерегайтесь, однако, что это может привести к ужасным ошибкам.
magu_
@ BjörnPollex Можно ли менять return dict.get(self, key)на это return super().get(key)? Тогда, если я решу использовать OrderedDict вместо dict, например, мне не придется беспокоиться об изменении нескольких строк кода.
Вуд
@ Вуд Да, это было бы намного лучше!
Бьорн Поллекс
12

Я обычно использую defaultdict для подобных ситуаций. Вы предоставляете фабричный метод, который не принимает аргументов и создает значение, когда он видит новый ключ. Это более полезно, когда вы хотите вернуть что-то вроде пустого списка новых ключей ( см. Примеры ).

from collections import defaultdict
d = defaultdict(lambda: None)
print d['new_key']  # prints 'None'
работа
источник
19
Проблема в defaultdictтом, что он будет расти каждый раз, когда запрашивается несуществующий элемент.
Бьорн Поллекс
8

Вы можете использовать метод dictобъекта get(), как уже предлагали другие. В качестве альтернативы, в зависимости от того, что именно вы делаете, вы можете использовать такой try/exceptнабор:

try:
   <to do something with d[key]>
except KeyError:
   <deal with it not being there>

Который считается очень "питонским" подходом к рассмотрению дела.

Мартино
источник
7

Однострочное решение будет:

item['key'] if 'key' in item else None

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

например.

row = [item['key'] if 'key' in item else 'default_value']
imapotatoe123
источник
5

Как уже говорили другие, вы можете использовать get ().

Но чтобы проверить ключ, вы также можете сделать:

d = {}
if 'keyname' in d:

    # d['keyname'] exists
    pass

else:

    # d['keyname'] does not exist
    pass
Марек П
источник
Теперь я вижу, что вы уже знаете, как это сделать. Я собирался удалить свой пост, но я оставлю его для справки для других.
Марек П
4
Этот подход обычно требует, чтобы ключ дважды просматривался, когда он там, что, вероятно, является причиной getметода.
Мартино
0

Я был озадачен тем, что было возможно в python2 против python3. Я отвечу на это, основываясь на том, что я сделал для python3. Моя цель была проста: проверить, дал ли ответ json в формате словаря ошибку или нет. Мой словарь называется «токен», а ключ, который я ищу, - «ошибка». Я ищу ключ "ошибка", и если его там не было, он установил его в значение None, тогда проверка - это значение None, если так, продолжайте с моим кодом. Оператор else будет обрабатываться, если у меня есть ключ «ошибка».

if ((token.get('error', None)) is None):
    do something
FastGTR
источник
-2

Если вы можете сделать это с помощью встроенной Falseфункции hasattr :

e=dict()
hasattr(e, 'message'):
>>> False
Evhz
источник