Что означает 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()) и найдите разницу.
- Опечатка. В словаре
"зелье", а в запросе"зеле". Сообщение KeyError покажет именно ошибочное написание. - Регистр букв.
"Меч"с большой буквы и"меч"с маленькой — разные ключи. Особенно часто так бывает с вводом пользователя. - Пробелы по краям. Строка, прочитанная из ввода или файла, может содержать пробел в конце. В сообщении он виден внутри кавычек:
'меч '. - Строка вместо числа.
input()всегда возвращает строку, поэтому"2"не найдёт ключ2. Приведите тип черезint(), иначе совпадения не получится. - Ключ ещё не добавлен или уже удалён. Программа читает пару раньше, чем записала, или после
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) удаляет и возвращает значение, а при отсутствии ключа спокойно вернёт второй аргумент.