Обработка исключений через try-except
Содержание курса
Перехват конкретного типа исключения
Можно написать except: без указания типа — это работает, но это грубый инструмент. На практике тебе нужно знать не просто «что-то пошло не так», а именно что: пользователь ввёл не число или кто-то делит на ноль. Для этого после except указывают конкретный класс исключения:
except ValueError:
...
При такой записи блок сработает только если возникло именно ValueError. Любое другое исключение — ZeroDivisionError, TypeError, что угодно — пройдёт мимо этого except и либо будет поймано следующим обработчиком, либо уронит программу с traceback. Типизированный except — это фильтр, а не универсальный пылесос. Почему голый except: без типа опасен — разберём подробно в секции про типичные ошибки; пока сосредоточимся на том, как правильно указывать тип.
Пример 1: ValueError при вводе числа
int() вызывает ValueError, когда строка не является целым числом. Именно это происходит, если пользователь вводит "abc" или "12.5":
try:
n = int(input("Введите целое число: "))
print("Вы ввели:", n)
except ValueError:
print("Ошибка: нужно ввести целое число, а не текст")
print("Программа продолжает работу")
Если пользователь вводит "abc" — int("abc") бросает ValueError, Python немедленно прыгает в except ValueError:, печатает сообщение, и программа продолжается. Строка print("Вы ввели:", n) при этом не выполняется вовсе — она осталась внутри try после точки падения.
Если пользователь вводит 42 — ValueError не возникает, except пропускается, оба print отрабатывают нормально.
Пример 2: ZeroDivisionError при делении
Деление на ноль — отдельный тип исключения, и для него нужен свой except:
a = 10
b = 0
try:
result = a / b
print("Результат:", result)
except ZeroDivisionError:
print("Ошибка: делить на ноль нельзя")
print("Вычисление завершено")
При b = 0 строка a / b бросает ZeroDivisionError, блок except ZeroDivisionError: перехватывает его. При b = 5 исключения нет, результат печатается нормально, except не трогается.
Обрати внимание: except ValueError: не поймал бы ZeroDivisionError — и наоборот. Каждый except отвечает ровно за свой тип. Это и есть смысл типизированного перехвата: ты точно знаешь, какую именно ситуацию обрабатываешь, и пишешь осмысленное сообщение именно под неё.
Если нужно обработать оба типа в одном блоке try, можно написать два except подряд:
try:
n = int(input("Введите делитель: "))
result = 100 / n
print("100 /", n, "=", result)
except ValueError:
print("Ошибка: введите число, а не текст")
except ZeroDivisionError:
print("Ошибка: делить на ноль нельзя")
Python проверяет except-блоки сверху вниз и заходит в первый подходящий. Если пользователь вводит "abc" — срабатывает первый. Если вводит 0 — срабатывает второй. Это даёт разные, точные сообщения для разных ситуаций — именно то, что нужно пользователю.
