Все разделы
Выбрать школу

Школа. Увлечения. Большое будущее.

PROSCHOOLS · ОБРАЗОВАНИЕ РЯДОМ

Ваш город

Выберите город, чтобы находить образование и возможности рядом.

Как учитываем городКаталог и кнопки «Выбрать школу» покажут школы выбранного города.Онлайн-курсы, учебник, ГДЗ и задания к экзаменам доступны по всей России.

Популярные города

Будет выбран: Вся Россия

Учебные материалы останутся прежними.

Поиск по сайту

По всему сайтуШколы выбранного города — выше в результатах

С чего начнём?

↑ ↓ — выбрать результат · Enter — открыть · Esc — закрыть

Плановая обработка ошибок: try, except и собственные исключения

💻 Информатика · 9 класс

Ошибка не должна рушить программу неожиданно. Разберём механику try/except, почему except должен быть конкретным, как поднимать свои ValueError и зачем нужен finally.

Клавиатура в компьютерном классе
Иллюстрация к предмету «Информатика»Hmartil · Wikimedia Commons · CC BY-SA 4.0

Два вида ошибок

Пропущенная скобка или двоеточие могут вызвать SyntaxError при разборе исходного файла: его обычное выполнение не начнётся. Сам SyntaxError тоже является исключением; например, его можно перехватить при вызове compile для отдельной строки исходного кода. Во время выполнения встречаются и другие исключения: деление на ноль (ZeroDivisionError), обращение по несуществующему ключу (KeyError), плохое преобразование типа (ValueError). Исключения можно перехватывать и обрабатывать — этим мы и займёмся.

Как работает try/except

Блок try выполняется как обычно. Если внутри возникает исключение, оставшаяся часть try пропускается, и управление переходит к первому блоку except, чей тип подходит. Если подходящего обработчика здесь нет, исключение передаётся внешнему вызывающему коду; если его нигде не перехватят, выполнение завершится с ошибкой. При обычном управлении Python блок finally выполняется при выходе из try — и при исключении, и без него; в него помещают очистку. Это не гарантия при аварийном завершении или принудительном уничтожении процесса.

Пример 1. Строгий разбор числа

Напишем функцию, которая принимает строку с положительным целым числом и отклоняет неправильный формат или неположительное значение с понятным сообщением.

def parse_positive_int(text):
    number = int(text)          # ValueError для 'abc', '3.5', ''
    if number <= 0:
        raise ValueError(f'ожидалось число больше 0, получено {number}')
    return number

Здесь два источника ValueError: встроенное преобразование int(text) и наша проверка через raise. Одна функция отвечает за полный цикл проверки: вызывающий код получает либо число, либо ValueError — и может решить, что делать. Проверьте границы: '7' вернёт 7, а '0', '-2', 'abc', '3.5' и пустая строка выбросят ValueError.

Пример 2. Кошелёк с правилами

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

class Wallet:
    def __init__(self, balance):
        if balance < 0:
            raise ValueError('начальный баланс не может быть отрицательным')
        self.balance = balance

    def spend(self, amount):
        if amount <= 0:
            raise ValueError('сумма покупки должна быть положительной')
        if amount > self.balance:
            raise ValueError('недостаточно средств')
        self.balance -= amount
        return self.balance

Кошелёк(100), покупка на 30 вернёт 70. Попытка потратить 0, -10 или 60 при балансе 50 выбросит ValueError, а баланс останется прежним — неудачная операция не меняет данные.

Правило конкретного except

Официальный учебник рекомендует перечислять конкретные типы исключений и не перехватывать всё подряд: пустой except скроет и опечатку в коде тоже. Хороший стиль — ловить ValueError там, где ждёшь плохую строку, KeyError — там, где обращаешься к словарю. Если обработчиков несколько, помните: срабатывает первый подходящий, остальные пропускаются, поэтому ставьте частные типы раньше общих.

Пример 3. Мягкий режим: пропускаем плохие строки

def safe_sum(texts):
    total = 0
    skipped = []
    for text in texts:
        try:
            total += int(text)
        except ValueError:
            skipped.append(text)
    return total, skipped

safe_sum(['10', 'x', '5', 'y']) вернёт (15, ['x', 'y']). Это альтернатива строгому parse_positive_int: одна и та же ошибка может быть фатальной в одной программе и безобидной в другой — выбор делает программист.

Обработчик, else и очистка

try:
    result = parse_positive_int('7')
except ValueError:
    print('Неверное число')
else:
    print(result)
finally:
    print('Проверка закончена')

Получим 7 и строку «Проверка закончена». Если заменить '7' на 'x', выполнятся обработчик и finally. Else выполняется, когда try завершился без исключения. Return в finally может скрыть исходное исключение, поэтому такую очистку не используют для подмены результата.

Проверь себя

  1. Что произойдёт в parse_positive_int('3.5')? Ответ: ValueError от int() — строка с точкой не является записью целого числа.
  2. Когда выполнится finally, если в try ошибки не было? Ответ: тоже выполнится — finally отработает при обычном выходе из try.
  3. Почему except без типа опасен? Ответ: он перехватывает любые исключения, включая неожиданные ошибки программы, и мешает их заметить.
  4. Wallet(50); spend(60) — каким будет баланс после исключения? Ответ: 50, потому что raise сработал до изменения поля.

Кратко о главном

Исключения — ошибки времени выполнения, которые можно перехватывать. try/except ловит конкретные типы, finally выполняется при обычном выходе из try, raise позволяет отклонять плохие данные самому. Перехватывайте только те исключения, которые готовы обработать.

Связанные материалы

Источники и материалы