В этом руководстве мы расскажем, как обрабатывать исключения в Python с помощью try и except. Рассмотрим общий синтаксис и простые примеры, обсудим, что может пойти не так, и предложим меры по исправлению положения.
Зачастую разработчик может предугадать возникновение ошибок при работе даже синтаксически и логически правильной программы. Эти ошибки могут быть вызваны неверными входными данными или некоторыми предсказуемыми несоответствиями.
Для обработки большей части этих ошибок как исключений в Python есть блоки try и except.
Синтаксис конструкции try и except
Для начала разберем синтаксис операторов try и except в Python. Общий шаблон представлен ниже:
try:
# В этом блоке могут быть ошибки
except <error type>:
# Сделай это для обработки исключения;
# выполняется, если блок try выбрасывает ошибку
else:
# Сделай это, если блок try выполняется успешно, без ошибок
finally:
# Этот блок выполняется всегда
Давайте посмотрим, для чего используются разные блоки.
Блок try
Блок try — это блок кода, который вы хотите попробовать выполнить. Однако во время выполнения из-за какого-нибудь исключения могут возникнуть ошибки. Поэтому этот блок может не работать должным образом.
Блок except
Блок except запускается, когда блок try не срабатывает из-за исключения. Инструкции в этом блоке часто дают некоторый контекст того, что пошло не так внутри блока try.
Если собираетесь перехватить ошибку как исключение, в блоке except нужно обязательно указать тип этой ошибки. В приведенном выше сниппете место для указания типа ошибки обозначено плейсхолдером <error type> .
except можно использовать и без указания типа ошибки. Но лучше так не делать. При таком подходе не учитывается, что возникающие ошибки могут быть разных типов. То есть вы будете знать, что что-то пошло не так, но что именно произошло, какая была ошибка — вам будет не известно.
При попытке выполнить код внутри блока try также существует вероятность возникновения нескольких ошибок.
Например, вы можете попытаться обратиться к элементу списка по индексу, выходящему за пределы допустимого диапазона, использовать неправильный ключ словаря и попробовать открыть несуществующий файл – и все это внутри одного блока try.
В результате вы можете столкнуться с IndexError, KeyError и FileNotFoundError. В таком случае нужно добавить столько блоков except, сколько ошибок ожидается – по одному для каждого типа ошибки.
Блок else
Блок else запускается только в том случае, если блок try выполняется без ошибок. Это может быть полезно, когда нужно выполнить ещё какие-то действия после успешного выполнения блока try. Например, после успешного открытия файла вы можете прочитать его содержимое.
Блок finally
Блок finally выполняется всегда, независимо от того, что происходит в других блоках. Это полезно, когда вы хотите освободить ресурсы после выполнения определенного блока кода.
Примечание: блоки else и finally не являются обязательными. В большинстве случаев вы можете использовать только блок try, чтобы что-то сделать, и перехватывать ошибки как исключения внутри блока except.
Итак, теперь давайте используем полученные знания для обработки исключений в Python. Приступим!
Обработка ZeroDivisionError
Рассмотрим функцию divide(), показанную ниже. Она принимает два аргумента – num и div – и возвращает частное от операции деления num/div.
def divide(num,div):
return num/div
Вызов функции с разными аргументами возвращает ожидаемый результат:
res = divide(100,8) print(res) # Output # 12.5 res = divide(568,64) print(res) # Output # 8.875
Этот код работает нормально, пока вы не попробуете разделить число на ноль:
divide(27,0)
Вы видите, что программа выдает ошибку ZeroDivisionError:
# Output
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-19-932ea024ce43> in <module>()
----> 1 divide(27,0)
<ipython-input-1-c98670fd7a12> in divide(num, div)
1 def divide(num,div):
----> 2 return num/div
ZeroDivisionError: division by zero
Можно обработать деление на ноль как исключение, выполнив следующие действия:
- В блоке
tryпоместите вызов функцииdivide(). По сути, вы пытаетесь разделитьnumнаdiv(try в переводе с английского — «пытаться», — прим. перев.). - В блоке
exceptобработайте случай, когдаdivравен 0, как исключение. - В результате этих действий при делении на ноль больше не будет выбрасываться ZeroDivisionError. Вместо этого будет выводиться сообщение, информирующее пользователя, что он попытался делить на ноль.
Вот как все это выглядит в коде:
try:
res = divide(num,div)
print(res)
except ZeroDivisionError:
print("You tried to divide by zero :( ")
При корректных входных данных наш код по-прежнему работает великолепно:
divide(10,2) # Output # 5.0
Когда же пользователь попытается разделить на ноль, он получит уведомление о возникшем исключении. Таким образом, программа завершается корректно и без ошибок.
divide(10,0) # Output # You tried to divide by zero :(
Обработка TypeError
В этом разделе мы разберем, как использовать try и except для обработки TypeError в Python.
Рассмотрим функцию add_10(). Она принимает число в качестве аргумента, прибавляет к нему 10 и возвращает результат этого сложения.
def add_10(num):
return num + 10
Вы можете вызвать функцию add_10() с любым числом, и она будет работать нормально, как показано ниже:
result = add_10(89) print(result) # Output # 99
Теперь попробуйте вызвать функцию add_10(), передав ей в качестве аргумента не число, а строку.
add_10 ("five")
Ваша программа вылетит со следующим сообщением об ошибке:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-15-9844e949c84e> in <module>()
----> 1 add_10("five")
<ipython-input-13-2e506d74d919> in add_10(num)
1 def add_10(num):
----> 2 return num + 10
TypeError: can only concatenate str (not "int") to str
Сообщение об ошибке TypeError: can only concatenate str (not "int") to str говорит о том, что можно сложить только две строки, а не добавить целое число к строке.
Обработаем TypeError:
- В блок try мы помещаем вызов функции
add_10()с my_num в качестве аргумента. Если аргумент допустимого типа, исключений не возникнет. - В противном случае срабатывает блок
except, в который мы помещаем вывод уведомления для пользователя о том, что аргумент имеет недопустимый тип.
Это показано ниже:
my_num = "five"
try:
result = add_10(my_num)
print(result)
except TypeError:
print("The argument `num` should be a number")
Поскольку теперь вы обработали TypeError как исключение, при передаче невалидного аргумента ошибка не возникает. Вместо нее выводится сообщение, что аргумент имеет недопустимый тип.
The argument `num` should be a number
Обработка IndexError
Если вам приходилось работать со списками или любыми другими итерируемыми объектами, вы, вероятно, сталкивались с IndexError.
Это связано с тем, что часто бывает сложно отслеживать все изменения в итерациях. И вы можете попытаться получить доступ к элементу по невалидному индексу.
В этом примере список my_list состоит из 4 элементов. Допустимые индексы — 0, 1, 2 и 3 и -1, -2, -3, -4, если вы используете отрицательную индексацию.
Поскольку 2 является допустимым индексом, вы видите, что элемент с этим индексом (C++) распечатывается:
my_list = ["Python","C","C++","JavaScript"] print(my_list[2]) # Output # C++
Но если вы попытаетесь получить доступ к элементу по индексу, выходящему за пределы допустимого диапазона, вы столкнетесь с IndexError:
print(my_list[4])
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-7-437bc6501dea> in <module>()
1 my_list = ["Python","C","C++","JavaScript"]
----> 2 print(my_list[4])
IndexError: list index out of range
Теперь вы уже знакомы с шаблоном, и вам не составит труда использовать try и except для обработки данной ошибки.
В приведенном ниже фрагменте кода мы пытаемся получить доступ к элементу по индексу search_idx.
search_idx = 3
try:
print(my_list[search_idx])
except IndexError:
print("Sorry, the list index is out of range")
Здесь search_idx = 3 является допустимым индексом, поэтому в результате выводится соответствующий элемент — JavaScript.
Если search_idx находится за пределами допустимого диапазона индексов, блок except перехватывает IndexError как исключение, и больше нет длинных сообщений об ошибках.
search_idx = 4
try:
print(my_list[search_idx])
except IndexError:
print("Sorry, the list index is out of range")
Вместо этого отображается сообщение о том, что search_idx находится вне допустимого диапазона индексов:
Sorry, the list index is out of range
Обработка KeyError
Вероятно, вы уже сталкивались с KeyError при работе со словарями в Python.
Рассмотрим следующий пример, где у нас есть словарь my_dict.
my_dict ={"key1":"value1","key2":"value2","key3":"value3"}
search_key = "non-existent key"
print(my_dict[search_key])
В словаре my_dict есть 3 пары «ключ-значение»: key1:value1, key2:value2 и key3:value3.
Теперь попытаемся получить доступ к значению, соответствующему несуществующему ключу non-existent key.
Как и ожидалось, мы получим KeyError:
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-2-2a61d404be04> in <module>()
1 my_dict ={"key1":"value1","key2":"value2","key3":"value3"}
2 search_key = "non-existent key"
----> 3 my_dict[search_key]
KeyError: 'non-existent key'
Вы можете обработать KeyError почти так же, как и IndexError.
- Пробуем получить доступ к значению, которое соответствует ключу, определенному
search_key. - Если
search_key— валидный ключ, мы распечатываем соответствующее значение. - Если ключ невалиден и возникает исключение — задействуется блок except, чтобы сообщить об этом пользователю.
Все это можно видеть в следующем коде:
try:
print(my_dict[search_key])
except KeyError:
print("Sorry, that's not a valid key!")
# Output:
# Sorry, that's not a valid key!
Если вы хотите предоставить дополнительный контекст, например имя невалидного ключа, это тоже можно сделать. Возможно, ключ оказался невалидным из-за ошибки в написании. Если вы укажете этот ключ в сообщении, это поможет пользователю исправить опечатку.
Вы можете сделать это, перехватив невалидный ключ как <error_msg> и используя его в сообщении, которое печатается при возникновении исключения:
try:
print(my_dict[search_key])
except KeyError as error_msg:
print(f"Sorry,{error_msg} is not a valid key!")
Обратите внимание, что теперь в сообщении об ошибки указано также и имя несуществующего ключа:
Sorry, 'non-existent key' is not a valid key!
Обработка FileNotFoundError
При работе с файлами в Python часто возникает ошибка FileNotFoundError.
В следующем примере мы попытаемся открыть файл my_file.txt, указав его путь в функции open(). Мы хотим прочитать файл и вывести его содержимое.
Однако мы еще не создали этот файл в указанном месте.
my_file = open("/content/sample_data/my_file.txt")
contents = my_file.read()
print(contents)
Поэтому, попытавшись запустить приведенный выше фрагмент кода, мы получим FileNotFoundError:
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
<ipython-input-4-4873cac1b11a> in <module>()
----> 1 my_file = open("my_file.txt")
FileNotFoundError: [Errno 2] No such file or directory: 'my_file.txt'
А с помощью try и except мы можем сделать следующее:
- Попробуем открыть файл в блоке
try. - Обработаем
FileNotFoundErrorв блокеexcept, сообщив пользователю, что он попытался открыть несуществующий файл. - Если блок
tryзавершается успешно и файл действительно существует, прочтем и распечатаем содержимое. - В блоке
finallyзакроем файл, чтобы не терять ресурсы. Файл будет закрыт независимо от того, что происходило на этапах открытия и чтения.
try:
my_file = open("/content/sample_data/my_file.txt")
except FileNotFoundError:
print(f"Sorry, the file does not exist")
else:
contents = my_file.read()
print(contents)
finally:
my_file.close()
Обратите внимание: мы обработали ошибку как исключение, и программа завершает работу, отображая следующее сообщение:
Sorry, the file does not exist
Теперь рассмотрим случай, когда срабатывает блок else. Файл my_file.txt теперь присутствует по указанному ранее пути.

Вот содержимое этого файла:

Теперь повторный запуск нашего кода работает должным образом.
На этот раз файл my_file.txt присутствует, поэтому запускается блок else и содержимое распечатывается, как показано ниже:

Надеемся, теперь вы поняли, как обрабатывать исключения при работе с файлами.
Заключение
В этом руководстве мы рассмотрели, как обрабатывать исключения в Python с помощью try и except.
Также мы разобрали на примерах, какие типы исключений могут возникать и как при помощи except ловить наиболее распространенные ошибки.
Надеемся, вам понравился этот урок. Успехов в написании кода!
Перевод статьи «Python Try and Except Statements – How to Handle Exceptions in Python».

