Почему dict.get (ключ) вместо dict [ключ]?

650

Сегодня я наткнулся на dictметод, getкоторый, учитывая ключ в словаре, возвращает соответствующее значение.

Для чего эта функция полезна? Если я хочу найти значение, связанное с ключом в словаре, я могу просто сделать dict[key], и он возвращает то же самое:

dictionary = {"Name": "Harry", "Age": 17}
dictionary["Name"]
dictionary.get("Name")
stensootla
источник
1
dictionary["foo"]и dictionary.get("foo")вести себя по-другому, хотя.
Никлас Б.
34
dictionary.get("Age") такой же , как писать , dictionary["Age"] or None так что неявно обрабатывает KeyError исключение
yosemite_k
5
@yosemite_k Возможно, мне здесь не хватает некоторого контекста, но он dictionary['non-existent key'] or Noneдолжен и все же поднимает KeyErrorдля меня (до v3.6). Можете ли вы объяснить, что вы имеете в виду?
NIVK
@nivk dictionary ['несуществующий ключ'] вызывает ошибку, и эта ошибка должна быть явно обработана. если вместо этого вы используете dictionary.get () (который буквально функционирует как словарь ['несуществующий ключ'] или None), это исключение обрабатывается неявно.
yosemite_k

Ответы:

995

Это позволяет вам указать значение по умолчанию, если ключ отсутствует:

dictionary.get("bogus", default_value)

возвращает default_value(что бы вы ни выбрали), тогда как

dictionary["bogus"]

поднимет KeyError.

Если опущено, default_valueесть Noneтакое, что

dictionary.get("bogus")  # <-- No default specified -- defaults to None

возвращается так Noneже, как

dictionary.get("bogus", None)

было бы.

unutbu
источник
1
Будет ли это так же, как dictionary.get("bogus") or my_default? Я видел, как люди используют его в некоторых случаях, и мне было интересно, есть ли какое-то преимущество в использовании одного вместо другого (кроме читабельности)
Algorithmatic
15
@MustafaS: Если "bogus"является ключом dictionaryи dictionary.get("bogus")возвращает значение, которое оценивается как False в логическом контексте (т. Е. Значение Falsey), такое как 0 или пустая строка '', тогда dictionary.get("bogus") or my_defaultбудет оцениваться, my_defaultтогда как dictionary.get("bogus", my_default)будет возвращено значение Falsey. Так что нет, dictionary.get("bogus") or my_defaultне эквивалентно dictionary.get("bogus", my_default). Какой из них использовать, зависит от желаемого вами поведения.
unutbu
3
@MustafaS: например, предположим x = {'a':0}. Затем x.get('a', 'foo')возвращается, 0но x.get('a') or 'foo'возвращается 'foo'.
Unutbu
3
Одно возможное предостережение при использовании dictionary.get('key'): это может сбивать с толку, если значения в словаре None. Без указания возвращаемого значения (второй необязательный аргумент) невозможно проверить, не существует ли ключ или его значение None. В этом конкретном случае я хотел бы рассмотреть возможность использования try-except-KeyError.
Аарт Гуссенс
1
Стоит отметить, что выражение для указания значения по умолчанию оценивается в вызове get и поэтому оценивается при каждом доступе. Классическая альтернатива (с использованием обработчика KeyError или предиката) заключается в оценке значения по умолчанию, только если ключ отсутствует. Это позволяет создать замыкание / лямбду один раз и оценить любой отсутствующий ключ.
Том Стамбо
143

Какой dict.get()метод?

Как уже упоминалось, getметод содержит дополнительный параметр, который указывает пропущенное значение. Из документации

get(key[, default])

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

Примером может быть

>>> d = {1:2,2:3}
>>> d[1]
2
>>> d.get(1)
2
>>> d.get(3)
>>> repr(d.get(3))
'None'
>>> d.get(3,1)
1

Есть ли улучшения скорости где-нибудь?

Как уже упоминалось здесь ,

Кажется, что все три подхода в настоящее время демонстрируют схожую производительность (в пределах примерно 10% друг от друга), более или менее независимую от свойств списка слов.

Ранее getбыло значительно медленнее, однако теперь скорость почти сопоставима с дополнительным преимуществом возврата значения по умолчанию. Но чтобы очистить все наши запросы, мы можем протестировать довольно большой список (обратите внимание, что тест включает в себя поиск только всех допустимых ключей)

def getway(d):
    for i in range(100):
        s = d.get(i)

def lookup(d):
    for i in range(100):
        s = d[i]

Теперь синхронизируем эти две функции, используя timeit

>>> import timeit
>>> print(timeit.timeit("getway({i:i for i in range(100)})","from __main__ import getway"))
20.2124660015
>>> print(timeit.timeit("lookup({i:i for i in range(100)})","from __main__ import lookup"))
16.16223979

Как мы видим, поиск выполняется быстрее, чем поиск, так как поиск функции отсутствует. Это можно увидеть черезdis

>>> def lookup(d,val):
...     return d[val]
... 
>>> def getway(d,val):
...     return d.get(val)
... 
>>> dis.dis(getway)
  2           0 LOAD_FAST                0 (d)
              3 LOAD_ATTR                0 (get)
              6 LOAD_FAST                1 (val)
              9 CALL_FUNCTION            1
             12 RETURN_VALUE        
>>> dis.dis(lookup)
  2           0 LOAD_FAST                0 (d)
              3 LOAD_FAST                1 (val)
              6 BINARY_SUBSCR       
              7 RETURN_VALUE  

Где это будет полезно?

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

 if key in dic:
      val = dic[key]
 else:
      val = def_val

Для одной строки, val = dic.get(key,def_val)

Где это будет НЕ полезно?

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

Возможно ли иметь getподобную функцию в dict['key']?

Да! Нам нужно реализовать __missing__в подклассе dict.

Пример программы может быть

class MyDict(dict):
    def __missing__(self, key):
        return None

Небольшая демонстрация может быть

>>> my_d = MyDict({1:2,2:3})
>>> my_d[1]
2
>>> my_d[3]
>>> repr(my_d[3])
'None'
Бхаргав Рао
источник
32
Золотой стандарт StackOverflow отвечает!
Apollo Data
1
Еще один хороший тест будет if k in dict and dict[k]:против if dict.get(k):. Это касается ситуации , когда нам нужно проверить , если ключ существует, и если «да» - то , что значение ?, что - то вроде: dict = {1: '', 2: 'some value'}.
TitanFighter
7
Пожалуйста, помните, что значение по умолчанию оценивается независимо от значения в словаре, поэтому вместо dictionary.get(value, long_function())одного можно подумать об использованииdictionary.get(value) or long_function()
Kresimir
Ах @ Kresimir, правда. Я получил этот вопрос в одном из интервью, с которым я столкнулся (я не знал об этом, когда я первоначально опубликовал этот ответ). Спасибо, что напомнили мне об этом.
Бхаргав Рао
33

getпринимает второе необязательное значение. Если указанный ключ не существует в вашем словаре, то это значение будет возвращено.

dictionary = {"Name": "Harry", "Age": 17}
dictionary.get('Year', 'No available data')
>> 'No available data'

Если вы не дадите второй параметр, None будет возвращено.

Если вы используете индексирование как в dictionary['Year'], несуществующие ключи будут повышаться KeyError.

Падший ангел
источник
20

Я приведу практический пример очистки веб-данных с помощью python, во многих случаях вы будете получать ключи без значений, в этих случаях вы будете получать ошибки, если будете использовать словарь ['key'], тогда как dictionary.get ('key ',' return_otherwise ') не имеет проблем.

Точно так же, я бы использовал '' .join (list) вместо list [0], если вы попытаетесь захватить одно значение из списка.

Надеюсь, поможет.

[Править] Вот практический пример:

Скажем, вы вызываете API, который возвращает файл JOSN, который вам нужно проанализировать. Первый JSON выглядит следующим образом:

{"bids":{"id":16210506,"submitdate":"2011-10-16 15:53:25","submitdate_f":"10\/16\/2011 at 21:53 CEST","submitdate_f2":"p\u0159ed 2 lety","submitdate_ts":1318794805,"users_id":"2674360","project_id":"1250499"}}

Второй JOSN выглядит так:

{"bids":{"id":16210506,"submitdate":"2011-10-16 15:53:25","submitdate_f":"10\/16\/2011 at 21:53 CEST","submitdate_f2":"p\u0159ed 2 lety","users_id":"2674360","project_id":"1250499"}}

Обратите внимание, что во втором JSON отсутствует ключ submitdate_ts, что вполне нормально для любой структуры данных.

Поэтому, когда вы пытаетесь получить доступ к значению этого ключа в цикле, вы можете вызвать его с помощью следующего:

for item in API_call:
    submitdate_ts = item["bids"]["submitdate_ts"]

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

Подходящим способом кодирования этого может быть следующее:

for item in API_call:
    submitdate_ts = item.get("bids", {'x': None}).get("submitdate_ts")

{'x': Нет}, чтобы избежать получения ошибки на втором уровне. Конечно, вы можете повысить отказоустойчивость в коде, если выполняете очистку. Как сначала указать условие if

Кевин
источник
2
Хороший ответ, опубликованный перед любым другим, за который проголосовали бы больше, и, вероятно, был бы принят, если бы вы опубликовали несколько примеров кода (хотя +1 от меня)
Mawg говорит восстановить Monica
2
@Mawg Недавно у меня был скребковый проект для моего исследования. Это был вызов API и синтаксический анализ файлов JSON. У меня был мой РА сделать это. Одной из ключевых проблем, с которыми он столкнулся, было непосредственное обращение к ключу, когда многие ключи фактически отсутствуют. Я опубликую пример в тексте выше.
Кевин
спасибо за решение многомерного аспекта этого! Похоже, вы даже можете просто сделать {} вместо {'x': None}
bluppfisk
18

Цель состоит в том, чтобы вы могли дать значение по умолчанию, если ключ не найден, что очень полезно

dictionary.get("Name",'harry')
hackartist
источник
8

Нужно быть в курсе при использовании .get() :

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

Например, следующие результаты Noneне 'alt_value'соответствуют ожидаемым:

d = {'key': None}
d.get('key', 'alt_value')

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

Колтон Хикс
источник
1
Один из них заставил меня: \ Один из способов решить эту проблему - иметь, d.get('key') or 'alt_value'если вы знаете, что это может бытьNone
Даниэль Холмс
8

Для чего эта функция полезна?

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

fruits = ['apple', 'banana', 'peach', 'apple', 'pear']
d = {}
for fruit in fruits:
    if fruit not in d:
        d[fruit] = 0
    d[fruit] += 1

Используя .get()метод, вы можете сделать этот код более компактным и понятным:

for fruit in fruits:
    d[fruit] = d.get(fruit, 0) + 1
jetpack_guy
источник
4

Почему dict.get (ключ) вместо dict [ключ]?

0. Резюме

По сравнению с dict[key],dict.get обеспечивает запасное значение при поиске ключа.

1. Определение

get (key [, default]) 4. Встроенные типы - документация по Python 3.6.4rc1

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

d = {"Name": "Harry", "Age": 17}
In [4]: d['gender']
KeyError: 'gender'
In [5]: d.get('gender', 'Not specified, please add it')
Out[5]: 'Not specified, please add it'

2. Проблема это решает.

Если нет default value, вы должны написать громоздкие коды для обработки такого исключения.

def get_harry_info(key):
    try:
        return "{}".format(d[key])
    except KeyError:
        return 'Not specified, please add it'
In [9]: get_harry_info('Name')
Out[9]: 'Harry'
In [10]: get_harry_info('Gender')
Out[10]: 'Not specified, please add it'

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

3. Вывод

dict.get имеет дополнительную опцию значения по умолчанию для исключения, если ключ отсутствует в словаре

Исчисление
источник
0

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

print(dictionary.get("address")) # None
print(dictionary["address"]) # throws KeyError: 'address'

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

Поэтому вместо того, чтобы делать это (или что-то подобное):

score = None
try:
    score = dictionary["score"]
except KeyError:
    score = 0

Мы можем сделать это:

score = dictionary.get("score", 0)
# score = 0
אנונימי
источник
-1

В зависимости от использования следует использовать это get метод.

Example1

In [14]: user_dict = {'type': False}

In [15]: user_dict.get('type', '')

Out[15]: False

In [16]: user_dict.get('type') or ''

Out[16]: ''

Example2

In [17]: user_dict = {'type': "lead"}

In [18]: user_dict.get('type') or ''

Out[18]: 'lead'

In [19]: user_dict.get('type', '')

Out[19]: 'lead'
Muthuvel
источник