Перейти к содержанию
Educora
Средний15 мин11 / 42

Обработка ошибок: try и except

Не дай программе аварийно завершиться: распознавай исключения, перехватывай их через try/except/else/finally и вызывай свои с помощью raise.

Проверь себя
В этом уроке ты узнаешь
  • Узнавать самые частые исключения
  • Перехватывать ошибку через try и except и продолжать работу программы
  • Использовать else, finally и raise

Ты написал калькулятор. Пользователь вводит «двенадцать» вместо числа или делит на ноль — и программа останавливается с красным сообщением об ошибке. Такие программы никто не любит! Хорошая программа готова к ошибкам: она распознаёт проблему, понятно объясняет её пользователю и продолжает работу.

Что такое исключения?

Ошибки бывают двух видов. Синтаксические ошибки (SyntaxError) — это ошибки в записи кода, и программа даже не запускается. Если код написан правильно, но при выполнении что-то идёт не так, Python создаёт исключение (exception). Если исключение не перехвачено, программа останавливается, и Python показывает «traceback» — отчёт об ошибке:

Text
Traceback (most recent call last):
  File "main.py", line 2, in <module>
    print(10 / count)
ZeroDivisionError: division by zero
ИсключениеКогда возникаетПример
ValueErrorтип подходит, но само значение нетint('abc')
TypeErrorоперация невозможна для этого типа'5' + 5
ZeroDivisionErrorделение на ноль10 / 0
IndexErrorтакого индекса нет[1, 2][5]
KeyErrorв словаре нет такого ключа{}['a']
NameErrorпеременной с таким именем нетprint(scor)

try и except

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

Python
text = 'abc'
try:
    number = int(text)
    print('Number:', number)
except ValueError:
    print('That is not a number!')
print('The program continues.')
▸ Ожидаемый результат
That is not a number!
The program continues.
Присвой text значение '25' и сравни результат.

У одного try может быть несколько блоков except — каждый перехватывает свой тип исключения. Запись except ... as e сохраняет само исключение в переменной e; если её вывести, увидишь пояснение Python.

Python
def safe_divide(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        print('Cannot divide by zero!')
    except TypeError as e:
        print('Wrong type:', e)
    return None

print(safe_divide(10, 2))
print(safe_divide(5, 0))
print(safe_divide(5, 'x'))
▸ Ожидаемый результат
5.0
Cannot divide by zero!
None
Wrong type: unsupported operand type(s) for /: 'int' and 'str'
None

else и finally

  • Блок else выполняется, только если try завершился без ошибки, — туда пиши работу с успешным результатом.
  • Блок finally выполняется всегда — была ошибка или нет. Обычно в нём завершают работу: закрывают файл, выводят сообщение.
Python
for value in ['42', 'seven']:
    try:
        n = int(value)
    except ValueError:
        print(f'{value}: not a number')
    else:
        print(f'{value}: doubled is {n * 2}')
    finally:
        print('checked', value)
▸ Ожидаемый результат
42: doubled is 84
checked 42
seven: not a number
checked seven

raise: вызов собственного исключения

Иногда для Python всё в порядке, а для твоей программы — нет: например, возраст не может быть отрицательным. В таких случаях исключение можно вызвать самому с помощью raise. Код ниже имитирует ответы пользователя и принимает первый правильный возраст:

Python
answers = ['abc', '-3', '14']
for answer in answers:
    try:
        age = int(answer)
        if age <= 0:
            raise ValueError('age must be positive')
    except ValueError as e:
        print(f'Bad input {answer}: {e}')
    else:
        print('Accepted age:', age)
        break
▸ Ожидаемый результат
Bad input abc: invalid literal for int() with base 10: 'abc'
Bad input -3: age must be positive
Accepted age: 14
Задание

Преобразуй строки из списка data в числа с помощью int() и сложи их. На элементе, который нельзя преобразовать, программа не должна останавливаться: перехвати ошибку через try/except ValueError и выведи Skipped: и этот элемент. В конце выведи Total: и сумму.

Задание · Python
data = ['12', 'seven', '30', '4.5', '8']
total = 0
# for each item: try to add int(item) to total,
# on ValueError print Skipped: and the item
# print Total: and total
▸ Ожидаемый результат
Skipped: seven
Skipped: 4.5
Total: 50
Задание

На складе 100 тетрадей. Напиши функцию sell(stock, count): если count равен нулю или отрицателен, она вызывает ValueError('count must be positive'), если он больше остатка — ValueError('not enough in stock'), а иначе возвращает, сколько осталось. Цикл в заготовке проверяет каждую продажу через try/except — не меняй его.

Задание · Python
# define sell(stock, count) here

stock = 100
for count in [30, -5, 90, 50]:
    try:
        stock = sell(stock, count)
        print('Sold', count, '- left:', stock)
    except ValueError as e:
        print('Error:', e)
▸ Ожидаемый результат
Sold 30 - left: 70
Error: count must be positive
Error: not enough in stock
Sold 50 - left: 20

Главное

  • Исключение — ошибка во время выполнения; если его не перехватить, программа остановится.
  • try содержит рискованный код, а except перехватывает конкретное исключение.
  • else выполняется, только если ошибки не было, а finally — всегда.
  • Собственное исключение вызывают через raise: raise ValueError('...').
  • Последняя строка traceback показывает тип исключения и его причину.

Проверь себя

Вопросов: 10. Каждый правильный ответ приносит XP.

1 / 10
Какое исключение вызовет int('hello')?