Обработка исключений в Python

Программа спрашивает у пользователя возраст и прибавляет год:

Python 3.13
age = int(input("Сколько вам лет? "))
print("Через год будет", age + 1)

Пока вводят число, всё работает. Но стоит пользователю набрать «сорок» вместо 40, и int() не сможет превратить это в число: программа аварийно завершится с ошибкой ValueError, а строка с print уже не выполнится. Один неверный ввод роняет всю программу.

Обработка исключений нужна как раз для таких моментов: перехватить ошибку, среагировать на неё и продолжить работу, вместо того чтобы падать при первой же неожиданности.

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

Исключение — это ошибка, возникшая во время выполнения программы. По умолчанию оно прерывает работу, но его можно перехватить и обработать.

Блоки try-except

Основной механизм обработки исключений в Python — блок try-except. Он позволяет:

  • Изолировать потенциально опасный код
  • Перехватывать ошибки
  • Выполнять альтернативные действия
  • Продолжать выполнение программы

Синтаксис блока try-except

Python 3.13
try:
    # Рискованный код, который может вызвать исключение
except ТипИсключения:
    # Код, который выполнится при возникновении указанного исключения

Вот простой пример:

Python 3.13
try:
    # Код, который может вызвать исключение
    result = 10 / 0  # Деление на ноль вызовет ZeroDivisionError
except ZeroDivisionError:
    # Код, который выполнится при возникновении исключения
    print("Ошибка: деление на ноль!")
Ошибка: деление на ноль!

Полная структура блока try-except

Полная структура блока try-except включает дополнительные секции:

Python 3.13
try:
    # Рискованный код
except ТипИсключения1:
    # Обработка исключения типа 1
except ТипИсключения2:
    # Обработка исключения типа 2
else:
    # Выполняется, если в блоке try не возникло исключений
finally:
    # Выполняется всегда, независимо от наличия исключений

Обработка исключений разных типов

Последовательная обработка разных исключений

Можно обрабатывать разные типы исключений по-разному:

Python 3.13
try:
    # Несколько операций, которые могут вызвать разные исключения
    file_name = input("Введите имя файла: ")  # Допустим, введено "data.txt"
    file = open(file_name, "r")
    line = file.readline()
    number = int(line.strip())
    result = 100 / number
    print(f"Результат: {result}")
except FileNotFoundError:
    print(f"Файл {file_name} не найден")
except ValueError:
    print("Невозможно преобразовать данные в число")
except ZeroDivisionError:
    print("Ошибка: деление на ноль")
except Exception as e:
    print(f"Произошла неизвестная ошибка: {e}")
Файл data.txt не найден

Важно: Python проверяет блоки except в порядке их объявления и выполняет первый подходящий блок.

Обработка нескольких исключений одним блоком

Если для разных исключений нужна одинаковая обработка:

Python 3.13
try:
    value = int("abc")
    result = 10 / 0
except (ValueError, ZeroDivisionError):
    print("Произошла ошибка в вычислениях")
Произошла ошибка в вычислениях

Блоки else и finally

Блок else

Блок else выполняется только если в блоке try не возникло исключений:

Python 3.13
try:
    number = int("42")  # Это выполнится успешно
except ValueError:
    print("Это не число")
else:
    # Этот блок выполнится, так как исключения не было
    print(f"Успешно! Число: {number}")
    print(f"Квадрат числа: {number ** 2}")
Успешно! Число: 42
Квадрат числа: 1764

Блок else полезен, когда нужно выполнить код только после успешного выполнения рискованной операции.

Блок finally

Блок finally выполняется всегда, независимо от того, произошло исключение или нет:

Python 3.13
try:
    f = open("example.txt", "w")
    f.write("Привет, мир!")
    # Предположим, здесь может произойти исключение
except IOError:
    print("Произошла ошибка ввода-вывода")
finally:
    print("Закрытие файла")
    f.close()  # Файл будет закрыт в любом случае
Закрытие файла

Блок finally обычно используется для:

  • Освобождения ресурсов (закрытие файлов, соединений с базой данных)
  • Очистки временных данных
  • Логирования завершения операции

Получение информации об исключении

Используйте as для получения объекта исключения:

Python 3.13
try:
    result = 10 / 0
except ZeroDivisionError as e:
    print(f"Тип исключения: {type(e).__name__}")
    print(f"Сообщение: {e}")
Тип исключения: ZeroDivisionError
Сообщение: division by zero

Вызов исключений

Вы можете сами вызывать исключения с помощью оператора raise:

Python 3.13
def check_age(age):
    if age < 0:
        raise ValueError("Возраст не может быть отрицательным")
    if age < 18:
        print("Вы несовершеннолетний")
    else:
        print("Вы совершеннолетний")

try:
    check_age(-5)
except ValueError as e:
    print(f"Ошибка: {e}")
Ошибка: Возраст не может быть отрицательным

Создание собственных исключений

Можно создавать собственные классы исключений, наследуя их от стандартных:

Python 3.13
# Создаем собственный класс исключения
class InvalidEmailError(Exception):
    """Вызывается, когда email не соответствует формату"""
    pass

def validate_email(email):
    if "@" not in email:
        raise InvalidEmailError("Email должен содержать символ @")
    print(f"Email {email} корректен")

try:
    validate_email("user.example.com")
except InvalidEmailError as e:
    print(f"Ошибка валидации: {e}")
Ошибка валидации: Email должен содержать символ @

Практические рекомендации

1. Определяйте конкретные исключения

Python 3.13
# Плохо:
try:
    number = int("abc")
except:  # Перехватывает все исключения
    print("Ошибка")

# Хорошо:
try:
    number = int("abc")
except ValueError:
    print("Неверный формат числа")
Неверный формат числа

2. Минимизируйте код в блоке try

Python 3.13
# Хорошо:
try:
    file = open("data.txt", "r")
except FileNotFoundError:
    print("Файл не найден")
    file = None

if file:
    try:
        content = file.read()
    except:
        print("Ошибка при чтении файла")
    finally:
        file.close()
Файл не найден

3. Используйте else и finally правильно

Python 3.13
def get_value_from_list(my_list, index):
    try:
        value = my_list[index]
    except IndexError:
        print(f"Индекс {index} вне диапазона")
        return None
    else:
        # Этот код выполнится только если исключения не было
        print(f"Значение успешно получено")
        return value
    finally:
        # Этот код выполнится всегда
        print("Операция доступа к списку завершена")

result = get_value_from_list([1, 2, 3], 1)
print(f"Результат: {result}")
Значение успешно получено
Операция доступа к списку завершена
Результат: 2
result = get_value_from_list([1, 2, 3], 10)
print(f"Результат: {result}")
Индекс 10 вне диапазона
Операция доступа к списку завершена
Результат: None

Проверка понимания

Какой блок выполнится всегда, независимо от того, произошло исключение или нет?