Ошибка KeyError при работе со словарём: причины и способы обхода

Ошибки Pythonобновлено 07.10.20269 мин чтенияесть тренажёр

KeyError в Python — это ошибка, которая возникает, когда программа просит из словаря значение по ключу, которого там нет. Частые причины: опечатка, другой регистр букв, лишний пробел, число вместо строки. Помогают проверка in, метод get() и аккуратная подготовка ключей.

Загружаем…

Что означает KeyError в Python

KeyError в Python — это сообщение «в словаре нет такого ключа». После двоеточия интерпретатор печатает сам ключ, который не нашёлся, и это главная подсказка для исправления.

Словарь похож на гардероб с номерками: по номерку выдают куртку. Если принести номерок, которого нет, гардеробщик не выдаст чужую куртку, а скажет «такого номера нет». Python поступает так же: при обращении через квадратные скобки к отсутствующему ключу он останавливает программу. В редакторе выше лежит рюкзак героя игры. Запустите код: первая строка сработает, а вторая вызовет ошибку.

inventar = {"меч": 1, "зелье": 3, "ключ": 2}
print(inventar["щит"])
Traceback (most recent call last):
  File "main.py", line 2, in <module>
    print(inventar["щит"])
KeyError: 'щит'

В отличие от многих других ошибок, здесь нет длинного пояснения — только тип и отсутствующий ключ в кавычках. Кавычки важны: они показывают, что ключ — строка. Если бы искали число, кавычек бы не было: KeyError: 5. Работа словарей и исключение KeyError описаны в официальной документации Python[1]. Там же указано, что KeyError — родственник IndexError: оба относятся к ошибкам поиска. Документация Python доступна на английском и частично на русском, а примеры из неё можно запускать прямо в нашем редакторе.

Как устроен словарь: ключи и значения

Словарь — это набор пар «ключ: значение», где каждый ключ встречается только 1 раз. По ключу значение находится мгновенно, но только при точном совпадении ключа.

Слово «точное» здесь главное. Для Python строки "меч", "Меч" и "меч " с пробелом в конце — три разных ключа. Человек видит одно и то же слово, а словарь видит разные последовательности символов. Поэтому отсутствующий ключ часто «есть», только записан чуть иначе. Подробно создание, изменение и перебор словаря разобраны в уроке о словарях в Python.

ЗаписьЧто делаетЕсли ключа нет
d[k]Возвращает значениеKeyError
d[k] = vСоздаёт или заменяет паруСоздаёт новую пару, ошибки нет
k in dПроверяет наличиеВозвращает False
d.get(k, x)Возвращает значениеВозвращает x (или None)
d.setdefault(k, x)Возвращает значениеДобавляет пару k: x и возвращает x
del d[k]Удаляет паруKeyError
d.pop(k, x)Удаляет и возвращает значениеВозвращает x

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

Пять причин, почему ключа нет

Отсутствующий ключ появляется по 5 типичным причинам. Сравните ключ из сообщения с ключами словаря — выведите print(d.keys()) и найдите разницу.

  1. Опечатка. В словаре "зелье", а в запросе "зеле". Сообщение KeyError покажет именно ошибочное написание.
  2. Регистр букв. "Меч" с большой буквы и "меч" с маленькой — разные ключи. Особенно часто так бывает с вводом пользователя.
  3. Пробелы по краям. Строка, прочитанная из ввода или файла, может содержать пробел в конце. В сообщении он виден внутри кавычек: 'меч '.
  4. Строка вместо числа. input() всегда возвращает строку, поэтому "2" не найдёт ключ 2. Приведите тип через int(), иначе совпадения не получится.
  5. Ключ ещё не добавлен или уже удалён. Программа читает пару раньше, чем записала, или после del.

Четвёртая причина особенно незаметна: в сообщении KeyError будет '2' в кавычках, а в словаре — 2 без кавычек. Именно кавычки выдают разницу типов. Как работает ввод и почему он всегда даёт строку, рассказано в статье про функцию input.

kod = {1: "один", 2: "два"}
otvet = input("Число: ")
print(kod.get(int(otvet), "нет такого"))

Проверка через in

Оператор in — это самый понятный способ избежать KeyError: сначала спросить, есть ли ключ, и только потом брать значение.

inventar = {"меч": 1, "зелье": 3, "ключ": 2}
predmet = "щит"
if predmet in inventar:
    print(predmet, ":", inventar[predmet])
else:
    print("В рюкзаке нет предмета:", predmet)

Такая запись хороша, когда при отсутствии ключа нужно сделать что-то особенное: вывести сообщение, спросить ещё раз, добавить предмет. Проверка in работает только с ключами, а не со значениями: 3 in inventar вернёт False, хотя тройка есть среди значений. Для поиска по значениям есть inventar.values(). В спецификации языка, опубликованной Python Software Foundation, оператор in для словаря определён именно как проверка ключей. Руководство PEP 8 советует писать именно predmet in inventar, без лишнего вызова keys()[2].

Метод get и значение по умолчанию

Метод get() возвращает значение по ключу, а если ключа нет — значение по умолчанию. По умолчанию это None, но лучше указывать своё, например 0.

inventar = {"меч": 1, "зелье": 3}
print(inventar.get("зелье", 0))
print(inventar.get("щит", 0))
print(inventar.get("щит"))
3
0
None

Самое частое применение — подсчёт. Задача «сколько раз встречается каждое слово» без get() требует условия на каждом шаге, а с ним укладывается в одну строку внутри цикла. На первом появлении слова get() вернёт 0, к нему прибавится 1, и пара запишется в словарь.

tekst = "кот пёс кот ёж кот пёс"
schet = {}
for slovo in tekst.split():
    schet[slovo] = schet.get(slovo, 0) + 1
print(schet)
{'кот': 3, 'пёс': 2, 'ёж': 1}

Метод setdefault для списков в словаре

Если значения — списки, удобен setdefault(): он создаёт пустой список для нового ключа и сразу возвращает его, так что к нему можно добавить элемент.

gruppy = {}
for imya in ["Аня", "Борис", "Алёша", "Вера", "Аркадий"]:
    gruppy.setdefault(imya[0], []).append(imya)
print(gruppy)

Программа разложит имена по первой букве: на «А» — три имени, на «Б» и «В» — по одному. Без setdefault() первое же обращение gruppy["А"] закончилось бы ошибкой.

Регистр и пробелы: готовим ключ заранее

Если ключи приходят от пользователя, их нужно привести к одному виду: убрать пробелы методом strip() и перевести в нижний регистр методом lower(). Тогда «Меч », «МЕЧ» и «меч» совпадут.

inventar = {"меч": 1, "зелье": 3}
zapros = "  Меч "
kluch = zapros.strip().lower()
print(kluch in inventar, inventar.get(kluch, 0))

Важно готовить одинаково обе стороны: и ключи при создании словаря, и запрос при чтении. Если словарь собран с большими буквами, а запрос переведён в маленькие, совпадения не будет. Удобное правило, которое не даёт запутаться, — хранить все строковые ключи маленькими буквами без пробелов по краям. Методы строк собраны в материале про строки и их методы. Руководство PEP 8 отдельно не регулирует регистр ключей, но единообразие имён — общий принцип этого документа, и для ключей он работает так же хорошо.

«KeyError бывает только у словарей». Это не подтверждается: множество тоже вызывает её, если удалить отсутствующий элемент методом remove(). Для множеств есть безопасный discard(), который молча ничего не делает.

«Метод get всегда лучше квадратных скобок». Это миф: если ключ обязан быть в словаре, тихий None спрячет ошибку. Квадратные скобки честно остановят программу там, где данные неполные. В официальной документации Python оба способа описаны как равноправные: выбор зависит от того, нормально ли отсутствие ключа.

Когда get не поможет

Метод get() не поможет, если ключ отсутствует из-за ошибки в данных, а не из-за нормальной ситуации. В этих 4 случаях исправлять нужно источник ключей.

  • Ключ записан с опечаткой 1 раз при создании словаря. get() будет возвращать 0, и программа посчитает неправильно, не выдав ни одного сообщения.
  • Ключи — числа, а запрос — строка из 1 символа. Значение по умолчанию вернётся всегда: нужно приводить тип через int().
  • Вложенный словарь на 2 уровня. d.get("a").get("b") при отсутствии "a" даст уже AttributeError у None. Проверяйте каждый уровень.
  • Перебор словаря и удаление в 1 цикле. Python запрещает менять размер словаря во время перебора — получится RuntimeError. Перебирайте копию: for k in list(d):.

Чего делать нельзя

Нельзя лечить ошибку отсутствующего ключа, не посмотрев, какой ключ искали. Сообщение показывает его прямо в кавычках — это половина решения.

  • Нельзя заменять все квадратные скобки на get() не думая: так ошибки в данных станут невидимыми.
  • Не следует хранить ключи в разном регистре в одном словаре — выберите один вид и придерживайтесь его.
  • Не стоит забывать про int(), если ключи — числа, а значение приходит из input().
  • Не допускается удалять ключи из словаря во время перебора этого же словаря.
  • Не стоит писать if k in d.keys() — короче и понятнее if k in d.
  • Нельзя глушить ошибку пустым except: программа продолжит работу с неполными данными.

Похожая по смыслу ошибка у списков разобрана на странице об ошибке IndexError, а общий порядок разбора сообщений — в статье как читать ошибки Python.

Источники

[1] The Python Tutorial (официальная документация Python 3). Python Software Foundation. — синтаксис и встроенные функции.

[2] van Rossum G., Warsaw B., Coghlan N. PEP 8 — Style Guide for Python Code. Python Software Foundation, 2001.

[3] ФИПИ. Методические рекомендации для обучающихся по организации индивидуальной подготовки к ЕГЭ 2026 года. Информатика. М., 2026.

Вопросы и ответы

Почему в сообщении KeyError в Python только одно слово?

После двоеточия печатается сам ключ, который не нашёлся. Этого достаточно: сравните его со списком ключей словаря, и разница станет видна.

Что вернёт get, если не указать значение по умолчанию?

Вернёт None. При выводе это слово появится на экране, а в арифметике вызовет TypeError, поэтому для чисел лучше явно указывать 0.

Можно ли использовать список как ключ?

Нет, ключом может быть только неизменяемое значение: строка, число, кортеж. Попытка взять список даст TypeError с текстом «unhashable type: 'list'».

Как узнать все ключи словаря?

Выведите print(list(d.keys())) или просто переберите словарь циклом for k in d. Это первый шаг, когда ключ «точно есть», а программа с этим не согласна.

Встречаются ли словари на экзаменах?

В заданиях ЕГЭ на написание программ словари часто используют для подсчёта, хотя решение можно написать и без них[3]. Метод get() с нулём по умолчанию здесь экономит время. В школьной программе по ФОП словари не обязательны: в 9 классе изучают одномерные массивы, а словари обычно осваивают дополнительно.

Чем отличается pop от del?

del d[k] просто удаляет пару и падает, если ключа нет. d.pop(k, None) удаляет и возвращает значение, а при отсутствии ключа спокойно вернёт второй аргумент.