get: безопасное чтение из словаря
Метод get читает словарь без KeyError: без ключа вернёт None, со вторым аргументом — запасное значение. Сравниваем с квадратными скобками, разбираем арифметику с None и молчание get.
Редакция Питоники
В прошлом уроке строгий доступ d[ключ] падал с KeyError, стоило ключу отсутствовать. Иногда это ровно то, что нужно. Но чаще отсутствие ключа — нормальная ситуация: товара может не быть на складе, слова — в переводе, пользователя — в базе. Для таких случаев у словаря есть метод get — чтение без сюрпризов.
get: чтение без падений
Метод вызывается через точку, ключ передаётся в скобках. Для существующего ключа get ведёт себя ровно как квадратные скобки — вся разница видна на отсутствующем:
stock = {'молоко': 12, 'хлеб': 5}
print(stock.get('молоко'))
print(stock.get('кефир'))
12 None
Второй аргумент: значение по умолчанию
Для 'кефир' метод вернул None — специальное значение «здесь ничего нет»: программа не упала, а честно ответила. Но слово «None» в отчётах выглядит странно, а в арифметике и вовсе опасно. Поэтому у get есть второй аргумент — запасное значение, которое вернётся, если ключа нет:
stock = {'молоко': 12, 'хлеб': 5}
print(stock.get('кефир', 0))
total = stock.get('кефир', 0) + stock.get('хлеб', 0)
print(total)
0 5
Умолчание работает только при отсутствии ключа: если 'хлеб' на месте, вернётся его 5, а не 0. Здесь и главная польза: складывать запасы можно одной строкой, не проверяя заранее, какие позиции есть, — отсутствующие просто посчитаются нулями.
stock = {'молоко': 12}
found = stock.get('кефир', 0)
print(found)
print(stock)
0
{'молоко': 12}| d[ключ] | d.get(ключ, 0) | |
|---|---|---|
| Ключ есть | значение | значение |
| Ключа нет | KeyError — программа падает | умолчание 0 |
| Когда брать | ключ обязан существовать | отсутствие — норма |
Сценарий: отчёт по складу за неделю
Соберём задачу, в которой get проявляет себя по-разному в зависимости от того, как написан код. Есть словарь остатков: {'молоко': 12, 'хлеб': 5, 'сыр': 8}. Нужно посчитать, сколько всего единиц товара лежит на складе, и вывести остаток по каждой позиции, включая ту, которой на складе нет.
stock = {'молоко': 12, 'хлеб': 5, 'сыр': 8}
total = 0
for item in stock.values():
total += item
print('всего позиций:', len(stock))
print('сумма:', total)
всего позиций: 3 сумма: 25
Тут get вообще не понадобился: мы итерировались по значениям, а не искали ключ. Ошибка в этом коде другая и куда более коварная — если бы в словаре завелась позиция с количеством None, сложение сразу упало бы с TypeError. Значения словарей стоит проверять на тип так же внимательно, как ключи.
stock = {'молоко': 12}
for name in ['молоко', 'кефир']:
amount = stock.get(name, 0)
print(name, '-', amount)
молоко - 12 кефир - 0
Здесь get спасение: без него цикл упал бы на втором шаге. И заметьте — словарь не изменился, лишней пары 'кефир' не появилось. Если бы в коде вместо get стояло stock[name] = 0, в словаре появилась бы лишняя позиция с нулём, и len(stock) вырос бы на единицу. Иногда это безобидно, иногда — нет: в отчёте о товарах, которых нет в наличии, вдруг начинают числиться нули.
stock = {'молоко': 12, 'хлеб': 5}
stock.get('кефир', 0)
stock.get('сыр', 0)
print(stock)
print(len(stock))
{'молоко': 12, 'хлеб': 5}
2Ловушка молчания: опечатка, которую никто не заметит
Самая неприятная особенность get — не в том, что он возвращает None, а в том, что он не спрашивает. Ключ написан с опечаткой, программа его не находит, get вежливо отдаёт 0, и расчёт продолжается. Ошибки нет, предупреждения нет, в логах пусто. Сумма за месяц получается меньше на одну позицию, и понять, откуда дыра, можно только пересчитывая всё вручную.
Есть и вторая сторона молчания: get возвращает None и тогда, когда ключ есть, но значение действительно None. Для словаря с необязательными полями это нормально, но сравнивать нужно с is None, а не с == None. Разница на практике небольшая, а вот ошибка if not d.get('поле') — уже настоящая: она считает поле отсутствующим и в случае с значением 0, и в случае с пустой строкой, хотя поле есть.
order = {'id': 7, 'discount': 0}
print('discount в заказе:', 'discount' in order)
print('значение через not:', not order.get('discount'))
print('значение через is None:', order.get('discount') is None)
discount в заказе: True значение через not: True значение через is None: False
Ключ в заказе есть, значение равно нулю — а not всё равно говорит «правда». Значит, проверка «есть ли скидка» через not order.get('discount') отбросит заказ с нулевой скидкой так же, как заказ без скидки. Скидка 0 процентов и отсутствие скидки — разные вещи, и код должен это различать.
get и setdefault: похожи, но не одно и то же
У словаря есть ещё один метод, который снаружи выглядит как get, но работает иначе: setdefault. Он тоже принимает ключ и запасное значение, но если ключа нет — не просто вернёт умолчание, а добавит пару в словарь. Один вызов — и в словаре появилась новая запись.
stock = {'молоко': 12}
print(stock.get('кефир', 0))
print(stock)
print(stock.setdefault('кефир', 0))
print(stock)
0
{'молоко': 12}
0
{'молоко': 12, 'кефир': 0}Разница видна во второй строке вывода: после get в словаре по-прежнему одна пара, после setdefault — две. Метод удобен там, где пустой слот нужно действительно заполнить: накопление списка по ключу, счётчик, первое появление даты. Но в коде, который просто читает, setdefault становится ловушкой — он меняет словарь там, где этого никто не ждал.
В одном сервисе мы заменили d.get(key, []) на d.setdefault(key, []) — и через неделю словарь распух в десять раз: каждый запрос к несуществующему ключу оставлял после себя пустой список. Данные не испортились, но память уходила, а в логах было тихо. Если нужен именно список под ключом, берите defaultdict(list) — про него урок 12.
Что дальше
Теперь умеете читать мягко и понимаете, чем за это платите. Дальше — изменение словаря: как добавить пару, как заменить значение и почему ключ всегда остаётся один. В уроке 5 разбираем присваивание по ключу и историю с дубликатами, а в уроке 6 — удаление: del, pop и popitem.
Сначала предскажи ответ в голове — это главный навык программиста.
stock = {'чай': 3}
print(stock.get('кофе'))
print(stock.get('кофе', 0))
d = {'a': 10}
print(d.get('a', 99))
print(d.get('b', 99))
stock = {'молоко': 12}
stock.get('кефир', 0)
print(stock)
1. Что вернёт d.get('ключ'), если такого ключа в словаре нет?
2. Зачем get второй аргумент: d.get('кефир', 0)?
3. Ключ 'хлеб' есть в словаре. Что вернёт d.get('хлеб', 0), если под ним лежит 5?
4. В каком случае get навредит, а квадратные скобки спасут?
5. Что опасно делать с результатом d.get('кефир') без умолчания?
6. Словарь order = {'id': 7, 'discount': 0}. Что вернёт not order.get('discount')?
7. Чем опаснее get, чем строгий доступ d[ключ]?
8. Как отличить отсутствующий ключ от ключа со значением None?
Дан словарь stock = {'молоко': 12}. Выведи количество кефира через get с умолчанием 0, затем выведи суммарный запас молока и кефира, посчитанный тоже через get.
Что делает метод get у словаря в Python?
Читает значение по ключу без риска KeyError: если ключ есть, get вернёт его значение, как и квадратные скобки; если ключа нет — вернёт None или второй аргумент-умолчание: stock.get('кефир', 0).
Урок 3: KeyError и строгий доступЧем get лучше квадратных скобок?
Ниже — вопрос. Разница ровно одна: поведение при отсутствии ключа. Если отсутствие — норма (товара нет, слова нет), get удобнее: программа продолжит работу. Если ключ обязан быть, скобки честнее: KeyError сразу укажет на баг в данных.
Добавляет ли get отсутствующий ключ в словарь?
Нет. get только читает: вызов stock.get('кефир', 0) вернёт 0, но словарь останется прежним — пары 'кефир' в нём не появится. Добавить пару можно присваиванием: stock['кефир'] = 0.
Какое умолчание указывать в get?
То, которое корректно впишется в дальнейшую работу: 0 для числовых подсчётов, пустую строку для текста, пустой список для коллекций. Без умолчания вернётся None — его нельзя складывать с числами, поэтому в подсчётах всегда задавайте второй аргумент.
Почему get может привести к тихой ошибке?
Потому что метод не спрашивает, правильный ли ключ. Опечатка в имени ключа даёт умолчание вместо ошибки: программа продолжает считать, но итог получается неверным, и найти пропажу можно только вручную. Для ключей из конфигов, ручного ввода и внешних API надёжнее строгий доступ или проверка in.
Урок 7: проверка ключа оператором inКак отличить отсутствующий ключ от ключа со значением None?
Одного get мало: без умолчания он вернёт None в обоих случаях. Проверяйте наличие ключа оператором in — он смотрит именно на ключи, — или сравнивайте результат get с None через is None.
Урок 7: оператор inНужно ли ставить умолчание, если значение точно не None?
Да, если результат пойдёт в арифметику или в сравнение с числом. Умолчание 0 превращает потенциальный TypeError в предсказуемое число и делает намерение явным. В коде, где значение используется только как флаг присутствия, get без умолчания вполне уместен.
Понравился урок? Сошлитесь на него
«get ни на что не жалуется: опечатка stock.get('малоко', 0) вернёт 0, и сумма получится неверной — без единой ошибки в логах.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Словари · Урок 3
Доступ по ключу и KeyError
Что происходит при доступе по несуществующему ключу: настоящий traceback, построчный разбор KeyError, отлов через try/except и случаи, когда падение — правильное поведение.
Словари · Урок 5
Добавление и изменение пар в словаре
Одна операция на всё: d[ключ] = значение добавляет новую пару или заменяет старую. Плюс уникальность ключей, порядок вставки и счётчики, которые пишутся в одну строку.
Словари · Урок 7
in: проверка ключа в словаре
Оператор in отвечает на вопрос «есть ли такой ключ»: проверка перед доступом вместо KeyError, not in, грабли с проверкой значений и причина скорости поиска.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
json · Урок 8
Путь к значению: достаём данные из глубины
Цепочки data["user"]["name"] и data["items"][0]["price"], KeyError у отсутствующих полей и get с умолчанием — спуск по типичному ответу API без падений.
python достать значение из jsondict get python умолчание
ООП · Урок 2
__init__ и self: как рождается объект
__init__ задаёт объекту стартовое состояние, а self — это сам объект внутри его методов. Разбираем механику вызова hero.heal(30) до последней детали.
python __init__ методзначения по умолчанию python
Словари · Урок 17
Словарь как данные: разбор ответа API
Ответ API — это вложенный словарь: достаём поля по цепочке ключей, читаем безопасно через get с умолчанием, разбираем списки записей и собираем из ответа готовый отчёт.
python словарь apiвложенный словарь python