Чому dict.get (ключ) замість dict [key]?


649

Сьогодні я натрапив на dictметод, getякий, задавши ключ у словнику, повертає пов’язане значення.

З якою метою корисна ця функція? Якщо я хотів знайти значення, пов’язане з ключем у словнику, я можу просто зробити dict[key], і воно повертає те саме:

dictionary = {"Name": "Harry", "Age": 17}
dictionary["Name"]
dictionary.get("Name")

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.get () (який буквально функціонує як словник ['неіснуючий ключ'] або None), з цим винятком керується неявно.
yosemite_k

Відповіді:


991

Це дозволяє надати значення за замовчуванням, якщо ключ відсутній:

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)

би.


1
Це було б те саме, що dictionary.get("bogus") or my_default? Я бачив, як люди використовують його в деяких випадках, і мені було цікаво, чи є якась перевага використання одного замість іншого (крім читабельності)
Алгоритмічний

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.
Aart Goossens

1
Варто відзначити, що вираз для визначення значення за замовчуванням оцінюється у виклику "отримати", і тому оцінюється при кожному доступі. Класична альтернатива (використовуючи обробник KeyError або предикат) - це оцінити значення за замовчуванням, лише якщо ключ відсутній. Це дозволяє один раз створити закриття / лямбда і оцінити будь-який ключ, що відсутній.
Том Стамбо

142

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

Як уже згадувалося, getметод містить додатковий параметр, який вказує на відсутнє значення. З документації

get(key[, default])

Поверніть значення для ключа, якщо ключ є у словнику, інакше за замовчуванням. Якщо за замовчуванням не вказано, він за замовчуванням не має значення, щоб цей метод ніколи не піднімав 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!
Дані Аполлона


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()
Кресімір

Ах @ Кресімір, правда. Я отримав це питання в одному з інтерв'ю, з яким я стикався (я не знав про це, коли я спочатку опублікував цю відповідь). Дякуємо, що нагадали про це.
Bhargav Rao

32

getприймає друге необов’язкове значення. Якщо вказаного ключа у вашому словнику не існує, це значення буде повернуто.

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

Якщо ви не вкажете другий параметр, Noneбуде повернуто.

Якщо ви використовуєте індексацію як у dictionary['Year'], неіснуючі ключі піднімаються KeyError.


19

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

Аналогічно, я б використав "" .join (список) на відміну від списку [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': None} є, щоб уникнути помилки другого рівня. Звичайно, ви можете створити більше відмовок до коду, якщо ви робите скребки. Як спочатку вказати умову if


2
Хороша відповідь, розміщена перед будь-якою з інших, яка могла б бути відхилена більше, і, ймовірно, прийнята, якби ви розмістили кілька прикладів коду (хоч +1 від мене)
Мауг каже, що поверніть Моніку

2
@Mawg Нещодавно у мене був проект прокрутки для мого дослідження. Він закликав API та аналізував файли JSON в основному. Я змусив мене це зробити. Однією з ключових проблем, яку він мав, був прямий виклик ключа, коли багато клавіш фактично відсутні. Я викладу приклад у тексті вище.
кевін

дякую за вирішення багатовимірного аспекту цього! Здається, ви навіть можете просто зробити {} замість {'x': None}
bluppfisk

17

Мета полягає в тому, що ви можете дати значення за замовчуванням, якщо ключ не знайдено, що дуже корисно

dictionary.get("Name",'harry')

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

7

Дозвіл, про який слід знати .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
Даніель Холмс

4

Чому dict.get (ключ) замість dict [key]?

0. Підсумок

Порівнюючи з dict[key], dict.getзабезпечує резервне значення під час пошуку ключа.

1. Визначення

get (ключ [, за замовчуванням]) 4. Вбудовані типи - документація на Python 3.6.4rc1

Поверніть значення для ключа, якщо ключ є у словнику, інакше за замовчуванням. Якщо за замовчуванням не вказано, він за замовчуванням не має значення, щоб цей спосіб ніколи не викликав 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, - це те, що він отримує додатковий необов'язковий аргумент для значення за замовчуванням, тобто якщо ми намагалися отримати бальне значення студента, але у студента немає бального ключа, який ми можемо отримати a 0 замість цього.

Тож замість цього робити (чи щось подібне):

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

Ми можемо це зробити:

score = dictionary.get("score", 0)
# score = 0

-1

На основі використання слід використовувати цей getметод.

Приклад1

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

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

Out[15]: False

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

Out[16]: ''

Приклад2

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'
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.