Исключения Python KeyError и способы их обработки

Оглавление

Смотрите сейчас, к этому уроку прилагается соответствующий видеокурс, созданный командой Real Python. Посмотрите его вместе с письменным руководством, чтобы углубить свое понимание: Исключения KeyError в Python и как с ними обращаться

Исключение Python KeyError - это распространенное исключение, с которым сталкиваются новички. Знание того, почему может возникнуть проблема KeyError, и некоторых решений, предотвращающих остановку вашей программы, являются важными шагами к совершенствованию в качестве программиста на Python.

К концу этого урока вы будете знать:

  • Что обычно означает Python KeyError
  • Где еще вы могли бы увидеть KeyError в стандартной библиотеке
  • Как обращаться с KeyError, когда вы видите это

Бесплатный бонус: Нажмите здесь, чтобы получить нашу бесплатную шпаргалку по Python, которая знакомит вас с основами Python 3, такими как работа с данными типы, словари, списки и функции Python.

Что обычно означает Python KeyError

Python KeyError исключение возникает при попытке получить доступ к ключу, которого нет в словаре (dict).

В официальной документации Python говорится, что KeyError вызывается при обращении к ключу сопоставления и не найден в сопоставлении. Отображение - это структура данных, которая преобразует один набор значений в другой. Наиболее распространенным отображением в Python является словарь.

Код Python KeyError является типом исключения LookupError и означает, что возникла проблема с получением ключа, который вы искали. Когда вы видите KeyError, это означает, что искомый ключ не найден.

В приведенном ниже примере вы можете увидеть словарь (ages), определенный с учетом возраста трех человек. Когда вы пытаетесь получить доступ к ключу, которого нет в словаре, возникает сообщение KeyError:

>>> ages = {'Jim': 30, 'Pam': 28, 'Kevin': 33}
>>> ages['Michael']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'Michael'


Здесь попытка получить доступ к ключу 'Michael' в словаре ages приводит к появлению KeyError. В нижней части обратной связи вы получите соответствующую информацию:

  • Тот факт, что был поднят вопрос о KeyError
  • Ключ, который не удалось найти, который был 'Michael'

В предпоследней строке указано, какая строка вызвала исключение. Эта информация более полезна при выполнении кода на Python из файла.

Примечание: Когда в Python возникает исключение, это выполняется с помощью обратной трассировки. Обратная трассировка предоставляет вам всю необходимую информацию, позволяющую определить, почему возникло исключение и что его вызвало.

Научиться читать обратную трассировку Python и понимать, о чем она вам говорит, крайне важно для совершенствования в качестве программиста на Python. Чтобы узнать больше об обратной трассировке Python, ознакомьтесь с Разделом "Понимание обратной трассировки Python".

В приведенной ниже программе вы можете снова просмотреть словарь ages. На этот раз вам будет предложено ввести имя человека, чтобы получить возраст для:

 1# ages.py
 2
 3ages = {'Jim': 30, 'Pam': 28, 'Kevin': 33}
 4person = input('Get age for: ')
 5print(f'{person} is {ages[person]} years old.')


Этот код будет использовать имя, которое вы укажете в приглашении, и попытается получить возраст этого человека. Все, что вы введете в командной строке, будет использовано в качестве ключа к словарю ages в строке 4.

Повторяя неудачный пример из приведенного выше, мы получаем еще одну обратную трассировку , на этот раз с информацией о строке в файле, из которой вызван KeyError:

$ python ages.py
Get age for: Michael
Traceback (most recent call last):
File "ages.py", line 4, in <module>
  print(f'{person} is {ages[person]} years old.')
KeyError: 'Michael'


Программа завершает работу с ошибкой, если вы вводите ключ, которого нет в словаре. Здесь последние несколько строк обратной трассировки указывают на проблему. File "ages.py", line 4, in <module> указывает, в какой строке какого файла возникло результирующее исключение KeyError. Затем вам будет показана эта строка. Наконец, исключение KeyError содержит недостающий ключ.

Итак, вы можете видеть, что последняя строка обратной связи KeyError сама по себе не дает вам достаточно информации, но строки перед ней могут значительно приблизить вас к пониманию того, что пошло не так.

Примечание: Как и в примере выше, в большинстве других примеров в этом руководстве используются f-строки, которые были представлены в Python 3.6.

Где еще Вы могли бы увидеть Python KeyError в стандартной библиотеке

В подавляющем большинстве случаев Python KeyError вызывается, потому что ключ не найден в словаре или подклассе словаря (например, os.environ).

В редких случаях вы также можете увидеть, что он вызывается в других местах стандартной библиотеки Python, например, в модуле zipfile, если элемент не найден в ZIP-архиве. Однако эти места сохраняют то же семантическое значение, что и Python KeyError, который не находит запрошенный ключ.

В следующем примере вы можете увидеть использование класса zipfile.ZipFile для извлечения информации о ZIP-архиве с помощью .getinfo():

>>> from zipfile import ZipFile
>>> zip_file = ZipFile('the_zip_file.zip')
>>> zip_file.getinfo('something')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/path/to/python/installation/zipfile.py", line 1304, in getinfo
  'There is no item named %r in the archive' % name)
KeyError: "There is no item named 'something' in the archive"


На самом деле это не похоже на поиск по ключу в словаре. Вместо этого это вызов zipfile.ZipFile.getinfo(), который вызывает исключение.

Обратная трассировка также выглядит немного по-другому, поскольку в ней содержится немного больше информации, чем просто отсутствующий ключ: KeyError: "There is no item named 'something' in the archive".

И последнее, на что следует обратить внимание, это то, что строки, из-за которой возникло значение KeyError, в вашем коде нет. Это указано в коде zipfile, но предыдущие строки обратной трассировки указывают, какие строки в вашем коде вызвали проблему.

Когда Вам нужно создать Python KeyError в вашем собственном коде

Могут быть случаи, когда для имеет смысл вызвать исключение Python KeyError в вашем собственном коде. Это можно сделать, используя ключевое слово raise и вызвав исключение KeyError:

raise KeyError(message)


Обычно message является отсутствующим ключом. Однако, как и в случае с пакетом zipfile, вы могли бы предоставить немного больше информации, чтобы помочь следующему разработчику лучше понять, что пошло не так.

Примечание: Если вы хотите более подробно ознакомиться с использованием raise, ознакомьтесь с Python's raise: Эффективное создание исключений в вашем коде.

Если вы решите использовать Python KeyError в своем собственном коде, просто убедитесь, что ваш вариант использования соответствует семантическому значению, стоящему за исключением. Это должно означать, что искомый ключ не найден.

Как обращаться с Python KeyError Когда Вы его видите

Когда вы сталкиваетесь с KeyError, есть несколько стандартных способов справиться с этим. В зависимости от вашего варианта использования, некоторые из этих решений могут быть лучше других. Конечная цель состоит в том, чтобы предотвратить возникновение неожиданных KeyError исключений.

Обычное решение: .get()

Если KeyError вызывается в результате неудачного поиска ключа по словарю в вашем собственном коде, вы можете использовать .get(), чтобы вернуть либо значение, найденное по указанному ключу, либо значение по умолчанию.

Как и в предыдущем примере с поиском возраста, в следующем примере показан лучший способ получить возраст из словаря, используя ключ, указанный в командной строке:

 1# ages.py
 2
 3ages = {'Jim': 30, 'Pam': 28, 'Kevin': 33}
 4person = input('Get age for: ')
 5age = ages.get(person)
 6
 7if age:
 8    print(f'{person} is {age} years old.')
 9else:
10    print(f"{person}'s age is unknown.")


Здесь, в строке 5, показано, как вы можете получить значение возраста из ages, используя .get(). В результате age переменная будет иметь значение возраста, найденное в словаре для предоставленного ключа, или значение по умолчанию, None<<в данном случае .

На этот раз вы не получите исключение KeyError, вызванное использованием более безопасного метода .get() для получения возраста вместо того, чтобы пытаться получить доступ к ключу напрямую:

$ python ages.py
Get age for: Michael
Michael's age is unknown.


В приведенном выше примере выполнения KeyError больше не вызывается при вводе неверного ключа. Ключ 'Michael' не найден в словаре, но, используя .get(), мы получаем возвращенный None, а не поднятый KeyError.

Переменная age будет содержать либо возраст человека, указанный в словаре, либо значение по умолчанию (None по умолчанию). Вы также можете указать другое значение по умолчанию в вызове .get(), передав второй аргумент.

Это строка 5 из приведенного выше примера с другим возрастом по умолчанию, указанным с помощью .get():

age = ages.get(person, 0)


Здесь вместо 'Michael', возвращающего None, будет возвращено 0, потому что ключ не найден, а возвращаемое значение по умолчанию теперь 0.

Редкое решение: Проверка наличия ключей

Иногда возникает необходимость определить наличие ключа в словаре. В таких случаях использование .get() может не дать вам правильной информации. Получение None, возвращенного из вызова .get(), может означать, что ключ не был найден или что значение, найденное в ключе в словаре, на самом деле является None.

Для словаря или объекта, подобного словарю, вы можете использовать оператор in, чтобы определить, присутствует ли ключ в отображении. Этот оператор вернет логическое значение (True или False, указывающее, найден ли ключ в словаре.

В этом примере вы получаете response словарь из вызова API. Этот ответ может содержать ключевое значение error, определенное в ответе, которое указывает на то, что ответ находится в состоянии ошибки:

 1# parse_api_response.py
 2...
 3# Assuming you got a `response` from calling an API that might
 4# have an error key in the `response` if something went wrong
 5
 6if 'error' in response:
 7    ...  # Parse the error state
 8else:
 9    ...  # Parse the success state


Здесь есть разница в проверке наличия ключа error в response и получении значения по умолчанию из ключа. Это редкий случай, когда на самом деле вас интересует, есть ли ключ в словаре, а не значение этого ключа.

Общее решение: try except

Как и в случае с любым исключением, вы всегда можете использовать блок try except, чтобы изолировать потенциальный код, вызывающий исключение, и предоставить решение для резервного копирования.

Вы можете использовать блок try except в аналогичном примере, как и раньше, но на этот раз он содержит сообщение по умолчанию, которое будет напечатано, если в обычном случае будет выведено значение KeyError:

 1# ages.py
 2
 3ages = {'Jim': 30, 'Pam': 28, 'Kevin': 33}
 4person = input('Get age for: ')
 5
 6try:
 7    print(f'{person} is {ages[person]} years old.')
 8except KeyError:
 9    print(f"{person}'s age is unknown.")


Здесь вы можете увидеть обычный регистр в блоке try для ввода имени и возраста пользователя. Резервный вариант находится в блоке except, где, если в обычном случае отображается KeyError, то резервный вариант должен выводить другое сообщение.

try except Блочное решение также является отличным решением для других приложений, которые могут не поддерживать .get() или оператор in. Это также лучшее решение, если KeyError вызывается из кода другого пользователя.

Вот пример повторного использования пакета zipfile. На этот раз блок try except дает нам возможность предотвратить остановку программы из-за исключения KeyError:

>>> from zipfile import ZipFile
>>> zip = ZipFile('the_zip_file.zip')
>>> try:
...     zip.getinfo('something')
... except KeyError:
...     print('Can not find "something"')
...
Can not find "something"


Поскольку класс ZipFile не предоставляет .get(), как это делает словарь, вам нужно использовать решение try except. В этом примере вам не нужно заранее знать, какие значения допустимы для передачи .getinfo().

Заключение

Теперь вы знаете несколько распространенных случаев, когда может возникать исключение Python KeyError, и несколько отличных решений, которые вы могли бы использовать, чтобы предотвратить остановку вашей программы.

Теперь, когда в следующий раз вы увидите сообщение KeyError, вы будете знать, что это, вероятно, просто неправильный поиск по ключу в словаре. Вы также сможете найти всю необходимую информацию, чтобы определить, откуда взялась ошибка, просмотрев последние несколько строк обратной трассировки.

Если проблема заключается в поиске ключа по словарю в вашем собственном коде, то вы можете переключиться с доступа к ключу непосредственно в словаре на использование более безопасного метода .get() с возвращаемым значением по умолчанию. Если проблема не связана с вашим собственным кодом, то лучше всего использовать блок try except для управления потоком кода.

Исключения не обязательно должны быть пугающими. Как только вы научитесь понимать информацию, предоставляемую вам в их трассировках, и основную причину исключения, вы сможете использовать эти решения, чтобы сделать работу ваших программ более предсказуемой.

<статус завершения article-slug="python-keyerror" class="btn-group mb-0" data-api-article-bookmark-url="/api/v1/articles/python-keyerror/bookmark/" статус завершения data-api-article-url="/api/v1/articles/ошибка python-ключа/completion_status/"> <кнопка поделиться bluesky-text="Интересная статья на #Python от @realpython.com :" email-body="Ознакомьтесь с этой статьей на Python:%0A%0APython KeyError Исключения и как с ними справляться" email-subject="Статья на Python для вас" twitter-text="Интересная статья на #Python от @realpython:" url="https://realpython.com/python-keyerror /" url-title="Исключения Python KeyError и как с ними обращаться">

Смотрите сейчас, к этому уроку прилагается соответствующий видеокурс, созданный командой Real Python. Посмотрите его вместе с письменным руководством, чтобы углубить свое понимание: Исключения KeyError в Python и как с ними обращаться

Back to Top