Исключения и обработка ошибок в Python
Содержание
- Исключения и зачем они нужны
- Почему ошибки нужно обрабатывать
- Базовая конструкция try…except
- Обработка разных типов исключений
- Ручной вызов ошибок через raise
- Частые исключения в Python
- Практика
- Короткий итог
Исключения и зачем они нужны
Исключение в Python - это событие, которое возникает во время выполнения программы и сообщает: что-то пошло не по ожидаемому сценарию. Например, пользователь ввел текст вместо числа, файл не найден, индекс вышел за границы списка или программа попыталась поделить значение на ноль.
Если исключение не обработать, выполнение обычно прерывается. Но в реальных программах чаще нужно не просто “уронить” код, а объяснить проблему, пропустить некорректные данные, закрыть файл, повторить действие или показать пользователю понятное сообщение.
Почему ошибки нужно обрабатывать
Обработка ошибок полезна по нескольким причинам:
- программа продолжает работать там, где это возможно;
- пользователь получает понятное сообщение вместо длинного traceback;
- разработчику проще найти причину проблемы;
- код становится надежнее при работе с файлами, вводом, сетью и внешними данными.
Идея простая: мы заранее предполагаем, где может возникнуть ошибка, и описываем, что делать в такой ситуации.
Базовая конструкция try...except
В блок try помещают код, который может вызвать исключение. В блок except - реакцию на конкретную ошибку.
Первый раз мы встречали try...except в 02.07 - Циклы — теперь разберём механизм полностью.
try:
result = 12 / 0
except ZeroDivisionError:
print("Ошибка: нельзя делить на ноль")Вывод:
Ошибка: нельзя делить на ноль
Здесь Python пытается выполнить деление, получает ZeroDivisionError и переходит в соответствующий except.
Обработка разных типов исключений
В одном фрагменте кода можно обработать несколько ошибок отдельно. Это удобно, потому что причины проблем могут быть разными, а реакция на них - тоже.
try:
value = int(input("Введите число: "))
result = 24 / value
except ValueError:
print("Ошибка: нужно ввести именно число")
except ZeroDivisionError:
print("Ошибка: деление на ноль недопустимо")
except Exception as error:
print("Непредвиденная ошибка:", error)
else:
print(f"Результат: {result}")
finally:
print("Проверка завершена")Как читается этот код:
ValueErrorсработает, если строку нельзя преобразовать в число;ZeroDivisionErrorпоймает деление на ноль;Exception as errorперехватит остальные ошибки, если они не были обработаны выше;elseвыполнится только если исключений не было;finallyвыполнится всегда, независимо от результата.
finally часто используют для завершающих действий: закрыть файл, соединение, освободить ресурс или записать финальное сообщение.
Ручной вызов ошибок через raise
Иногда ошибка технически еще не произошла, но по логике программы значение уже недопустимо. Тогда исключение можно вызвать самостоятельно.
def divide(a, b):
if b == 0:
raise ZeroDivisionError("Делитель не может быть равен нулю")
return a / b
try:
print(divide(18, 0))
except ZeroDivisionError as error:
print("Ошибка:", error)Вывод:
Ошибка: Делитель не может быть равен нулю
raise помогает явно зафиксировать правило: если входные данные нарушают условие, функция не делает вид, что все нормально.
Частые исключения в Python
ValueError- значение неподходящее, хотя тип может быть правильным.TypeError- операция применена к неподходящему типу данных.ZeroDivisionError- попытка деления на ноль.FileNotFoundError- файл не найден.KeyError- в словаре нет нужного ключа.IndexError- индекс вышел за пределы последовательности.ImportError- модуль или объект не удалось импортировать.Exception- общий базовый класс для большинства обычных исключений.
Важно: лучше перехватывать конкретные исключения. Общий except Exception полезен как запасной вариант, но им не стоит заменять нормальную обработку известных ошибок.
Практика
-
Задача 1: безопасное деление
Написать функцию
safe_divide(a, b), которая делитaнаbи обрабатывает деление на ноль.def safe_divide(a, b): try: return a / b except ZeroDivisionError: return "Ошибка: деление на ноль" print(safe_divide(21, 3)) print(safe_divide(21, 0)) -
Задача 2: проверка имени файла
Написать функцию
read_text_file(filename), которая принимает имя файла и читает его содержимое.Условия:
- если имя файла пустое, вернуть сообщение
Имя файла не может быть пустым; - если файла нет, обработать
FileNotFoundError; - если файл найден, вернуть его содержимое.
def read_text_file(filename): try: if not filename: raise ValueError("Имя файла не может быть пустым") with open(filename, "r", encoding="utf-8") as file: return file.read() except ValueError as error: return str(error) except FileNotFoundError: return "Ошибка: файл не найден" - если имя файла пустое, вернуть сообщение
-
Задача 3: деление числа на элементы списка
Написать функцию
divide_by_items(numbers), которая делит120на каждый элемент списка.Нужно обработать:
- деление на ноль;
- элементы неподходящего типа;
- продолжение работы после проблемного элемента.
def divide_by_items(numbers): results = [] for item in numbers: try: results.append(120 / item) except ZeroDivisionError: print("Пропуск: деление на ноль") except TypeError: print(f"Пропуск: неподходящий тип данных ({item})") return results print(divide_by_items([4, 0, 6, "x", 10]))
Короткий итог
try...except помогает перехватывать ошибки и управлять поведением программы. else нужен для кода, который должен выполниться только при успешном try, finally - для действий, которые выполняются всегда, а raise - для явного создания исключения по правилам вашей логики. Чем точнее обработаны ошибки, тем устойчивее и понятнее становится программа.
⬅️ Назад: 03.01 - Функции | Далее: 03.03 - ООП Общая теория ➡️ Модуль: 03 - MOC