Обработка исключений в python
Общая информация
В некоторых ЯП ошибки отображаются с помощью специальных возвращаемых значений. В Python используется исключение: код, который выполняется, когда происходит связанная с ним ошибка. Лучше добавлять обработчик ошибок везде, где потенциально ошибки могут появится.
Иерархия исключений
Полный список исключений можно найти по ссылке: Иерархия исключений в python.
Основные конструкции для обработки исключений
Блок try
Код в блоке try
python попытается выполнить, а если не получится - выполнится блок except
.
Блок except
Не используйте bare except (голый, без указания конкретных исключений). Примеры правильного применения:
try:
<code>
except IndexError:
<code>
Применение as
:
try:
<code>
except IndexError as exc:
print(f"Exception: {exc}")
Multiple exceptions:
try:
<code>
except (IndexError, ImportError, NameError) as exc:
print(f"Exception: {exc}")
Блок else
Код в else
выполнится, если не был вызван блок except
, то есть не отловились исключения, и не было ошибок:
try:
<code>
except (IndexError, ImportError, NameError) as exc:
print(f"Exception: {exc}")
else:
print("Код был успешно выполнен")
Блок finally
Код в finally
выполнится в любом случае. Например:
try:
tmp_file = open("file.txt", "w")
input_numbers = int(input("Enter the numbers: "))
except (IsADirectoryError, PermissionError, ValueError) as exc:
print(f"Exception: {exc}")
else:
print(f"Строка {input_numbers} успешно записана в файл {tmp_file.name}")
finally:
tmp_file.close()
Таким образом, файл закроется в любом случае. Вариант без finally
не гарантирует закрытие файла, так как программа может завершиться из-за неопределенных в except
исключений.
Использование raise
Вместо самодельного прерывания, используйте raise
, который предназначен для этой задачи:
line_count = 0
for line in text:
length = len(line)
if length < 3:
line_count += 1
raise BaseException(f"Длина {line_count} строки меньше 3 символов")
Проброс исключения
Пробросом исключения называют передачу информации об ошибке дальше по коду, не обрабатывая её в текущем месте. Делается с помощью
raise
.
Пример функции divide()
, которая пробрасывает свое исключение, чтобы передать вызывающему коду информацию об ошибке:
def divide(a, b):
if b == 5:
raise ValueError("Не надо делить на 5 😡")
return a / b
try:
result = divide(10, 5)
except ValueError as e:
print(e)
Output:
Не надо делить на 5 😡
Еще один пример проброса исключения:
def read_file(filename):
try:
with open(filename, 'r') as f:
return f.read()
except FileNotFoundError:
raise FileNotFoundError(f"Файл {filename} не найден.")
try:
content = read_file("неcуществующий_файл.txt")
except FileNotFoundError as e:
print(e)
Output:
Файл неcуществующий_файл.txt не найден.
Пример проброса исключения вверх по стеку:
min = 100
try:
if min > 10:
raise Exception('min must be less than 10')
except Exception:
print('Моя ошибка')
raise
Output:
> Моя ошибка
> Traceback (most recent call last):
> File "test.py", line 5, in <module>
> raise Exception('min must be less than 10')
> Exception: min must be less than 10
Обработка нескольких исключений
Если предполагается, что могут возникнуть несколько типов исключений, лучшим решением будет предоставить отдельный обработчик для каждого из них:
>>> short_list = [1, 2, 3]
>>> while True:
value = input('Position [q to quit]? ')
if value == 'q':
break
try:
position = int(value)
print(short_list[position])
except IndexError as err:
print('Bad index:', position)
except Exception as other:
print('Something else broke:', other)
Output:
Position [q to quit]? 1
2
Position [q to quit]? 3
Bad index: 3
Position [q to quit]? two
Something else broke: invalid literal for int() with base 10: 'two'
Position [q to quit]? q
Создание своих исключений
Для создания своих исключений нужно определить новый тип объекта с помощью класса. Пример:
>>> class UppercaseException(Exception):
pass
>>> words = ['eeenie', 'meenie', 'miny', 'MO']
>>> for word in words:
if word.isupper():
raise UppercaseException(word)
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
__main__.UppercaseException: MO
Для вывода информации об исключении:
>>> try:
raise OopsException('panic')
except OopsException as exc:
print(exc)
panic
Соус: Книга “Простой Python” → Глава 9. “Функции” → “Исключения”