Повернути немає, якщо клавіша словника недоступна


489

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

Однак Python створює KeyErrorвиняток, якщо шукати ключ, який не існує. Я знаю, що можу перевірити ключ, але шукаю щось більш чітке. Чи є спосіб просто повернутися, Noneякщо ключ не існує?


74
Просто використовуйте .get(key)замість[key]
Gabe

12
Дікт викликає виключення KeyError. Він не "повертає key_error".
Бер

3
Отримати доступ до ключа та знайти виняток - це абсолютно добре в Python. Це навіть добре відомий і часто використовуваний шаблон дизайну. Якщо замість цього повернути None, неможливо зберігати None як значення, яке може бути актуальним у деяких випадках.
Бер

1
Іноді ви хочете, щоб записи "None" в словнику були відсутні, а пропущені записи були однаковими, у цьому випадку прийнята відповідь, здається, виконає цю роботу чудово.
cib

@Ber Я змінив питання, щоб уточнити. Ви могли це зробити і ви.
törzsmókus

Відповіді:


813

Можна використовувати dict.get()

value = d.get(key)

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

value = d.get(key, "empty")

47
Зауважте, що другий варіант із замовчуванням резервний все ще повернеться, Noneякщо ключ чітко відображений Noneу дикті. Якщо це не те, що ви хочете, ви можете використовувати щось подібне 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 (mapping) -> новий словник, ініціалізований із об'єкта відображення
     | (ключ, значення) пари
    ...
     |  
     | отримати (...)
     | D.get (k [, d]) -> D [k], якщо k в D, інакше d. d за замовчуванням до None.
     |  
    ...

22

Використовуйте dict.get

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


19

Ви повинні використовувати get()метод із dictкласу

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

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


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
nehem

@itsneo. Ви можете побудувати всю структуру NoneDicts. Це допоможе у випадку, якщо KeyErrorце станеться у найпотужнішому об’єкті. Інакше проблема полягає в тому, що після повернення Noneоб'єкта ви більше не можете підписатися на нього. Одним неприємним злом було б повернути ще один об'єкт, який тестує None. Однак остерігайтеся, що це може призвести до жахливих помилок.
magu_

@ BjörnPollex Чи можна змінити return dict.get(self, key)в return super().get(key)? Тоді, якщо, наприклад, я вирішу використовувати OrdersDict замість dict, мені не доведеться турбуватися про зміну кількох рядків коду.
Вуд

@Wood Так, це насправді було б набагато приємніше!
Бьорн Поллекс

12

Я зазвичай використовую вирок за замовчуванням у таких ситуаціях. Ви надаєте заводський метод, який не бере аргументів і створює значення, коли він бачить новий ключ. Це корисніше, коли ви хочете повернути щось на зразок порожнього списку на нових клавішах ( див. Приклади ).

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']

5

Як вже говорили інші, ви можете використовувати get ().

Але для перевірки ключа ви також можете зробити:

d = {}
if 'keyname' in d:

    # d['keyname'] exists
    pass

else:

    # d['keyname'] does not exist
    pass

Тепер я бачу, що ви вже знаєте, як це зробити. Я збирався видалити свою публікацію, але залишлю її для довідки для інших.
Marek P

4
Цей підхід, як правило, вимагає двічі переглянути ключ, коли він є, що, ймовірно, є причиною getметоду.
мартіно

0

Мене здивувало те, що було можливо в python2 проти python3. Я відповім на це, виходячи з того, що я в кінцевому підсумку робив для python3. Моя мета була проста: перевірити, чи відповідь json у форматі словника помилка чи ні. Мій словник називається "маркер", і мій ключ, який я шукаю, - "помилка". Я шукаю ключ "помилка", і якщо його там не було, встановивши його значення "None", то перевірка - це значення "None" (якщо немає), якщо так, продовжуйте використовувати мій код. Інше твердження буде справлятися, якщо в мене є ключ "помилка".

if ((token.get('error', None)) is None):
    do something

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