Перейти к содержанию

412 уроков, 25 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 7 из 20 Начальный 15 мин 100 XP

raise: бросаем исключение сами

До сих пор ошибки бросал Python. Теперь научимся бросать сами: raise ValueError с понятным текстом, когда данные нарушают правила программы.

Редакция Питоники

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

Нарушенное правило — это ошибка

Возраст -5 — не крах операции: Python спокойно хранит отрицательные числа. Крах логический: данные не соответствуют смыслу задачи. Молча продолжать с такими данными опасно — отчёт посчитает «минус пять лет». Правильная реакция — громкая: остановить обработку и объявить, что правило нарушено.

raise внутри try
age = -5
try:
    if age < 0:
        raise ValueError('возраст не может быть отрицательным')
    print('Принят возраст:', age)
except ValueError as e:
    print('Отклонено:', e)
Вывод
Отклонено: возраст не может быть отрицательным

Условие нашло нарушение — raise бросил ValueError с нашим текстом. Дальше всё знакомое: исключение полетело в ближайший except, обработчик поймал его через as e и напечатал сообщение. С точки зрения except нет никакой разницы, кто бросил ошибку — Python или наша строка кода.Raise — это штатный способ сказать «дальше с такими данными не работаю».

правильные данные проходят
age = 30
try:
    if age < 0:
        raise ValueError('возраст не может быть отрицательным')
    print('Принят возраст:', age)
except ValueError as e:
    print('Отклонено:', e)
Вывод
Принят возраст: 30

Условие не сработало, raise не выполнился — данные прошли насквозь и попали в печать приёма. Проверка не наказывает хорошие данные: она спит, пока правило не нарушено.

raise без ловли: честное падение

Что будет, если бросить исключение там, где рядом нет try? То же, что с любой непойманной ошибкой — traceback и остановка программы:

raise без обработчика
age = -5
if age < 0:
    raise ValueError('возраст не может быть отрицательным')
print('Продолжаем')
Вывод
Traceback (most recent call last):
  File "app.py", line 3, in <module>
    raise ValueError('возраст не может быть отрицательным')
ValueError: возраст не может быть отрицательным
Программа падает на строке с raise: ловить некому. В сообщении — наш собственный текст. Строка «Продолжаем» не выполнится.

raise превращает нарушенное правило данных в настоящую ошибку Python — с типом, понятным текстом и traceback. Traceback здесь указывает на нашу строку с raise, а в последней строке — тип и текст, которые мы выбрали. Для вызывающего кода это самое честное сообщение: правило нарушено, вот какое. Убрать проверку или заменить её молчаливой печатью — значит позволить плохим данным течь дальше по программе.

Текст ошибки — сообщение для людей

В скобках после типа пишется сообщение. Без него ошибка тоже бросится, но скажет только тип:

raise без текста
try:
    raise ValueError
except ValueError as e:
    print('Тип:', type(e).__name__)
    print('Сообщение:', repr(str(e)))
Вывод
Тип: ValueError
Сообщение: ''

Сообщение оказалось пустой строкой: рассказать, что именно не так, некому. Кто поймает такую ошибку — увидит тип, но не причину. Поэтому правило урока: raise всегда с текстом. Текст — это не украшение, а сама суть: он объясняет нарушенное правило словами.

два правила — два raise
login = 'a' * 25
try:
    if len(login) == 0:
        raise ValueError('логин пуст')
    if len(login) > 20:
        raise ValueError('логин длиннее 20 символов')
    print('Логин принят:', login)
except ValueError as e:
    print('Отклонено:', e)
Вывод
Отклонено: логин длиннее 20 символов

Две проверки, два raise с разными текстами. Сработало то нарушение, которое условие нашло первым: логин непустой, но длинный — вторая проверка остановила обработку. Каждый raise — это одно правило и одна формулировка: не «данные плохие вообще», а конкретно «логин длиннее 20 символов».

Проверка данных в цикле: брак мимо отчёта

Соберём рабочую схему: сумма оценок, где каждая выше сотни — нарушение правила. Нарушившие не роняют отчёт, а попадают в протокол:

raise в цикле с обработкой
scores = [90, 105, 70]
total = 0
for s in scores:
    try:
        if s > 100:
            raise ValueError(f'оценка {s} больше 100')
        total += s
    except ValueError as e:
        print('Пропущен:', e)
print('Сумма корректных:', total)
Вывод
Пропущен: оценка 105 больше 100
Сумма корректных: 160

Оценка 105 нарушила правило — raise остановил её обработку и бросил ошибку с её номером в тексте. Обработчик поймал, напечатал протокол, и цикл перешёл к семидесятке, которая вошла в сумму. f-строка в сообщении здесь не украшение: без неё протокол сказал бы «оценка больше 100» — а какую именно, осталось бы тайной.

Какой тип бросать

Бросать стоит стандартные типы — по смыслу нарушения. ValueError, если не подошло значение: отрицательный возраст, пустой логин, оценка больше ста. TypeError, если не подошёл сам тип данных: вместо числа пришла строка. Точный тип помогает обработчику: цепочка except из четвёртого урока различит «плохое значение» и «плохой тип».

НарушениеТипПример
Значение вне допустимого диапазонаValueErrorraise ValueError('возраст отрицательный')
Не тот тип данныхTypeErrorraise TypeError('ожидали число')
Ключа нет, а он обязателенKeyErrorraise KeyError('логин')
Операция преждевременнаRuntimeErrorraise RuntimeError('сначала откройте файл')

А вот бросать строку нельзя — даже если очень хочется сообщить текст. Исключение — это объект особого рода, и Python проверяет это строго:

raise строки не работает
raise 'что-то пошло не так'
Вывод
Traceback (most recent call last):
  File "app.py", line 1, in <module>
    raise 'что-то пошло не так'
TypeError: exceptions must derive from BaseException
Программа падает прямо на raise: бросать можно только объекты, унаследованные от BaseException — то есть классы исключений. Текст передаётся в скобках: raise ValueError('что-то пошло не так').

raise в общей схеме урока

  • raise ValueError('текст') бросает исключение с сообщением — выполнение останавливается на этой строке;
  • ближайший except ловит ваш raise так же, как ошибку Python: тип, сообщение через as e;
  • без обработчика ваш raise падает с traceback — и это правильно: вызывающий код узнаёт о нарушении;
  • текст пишите всегда и конкретно: правило, которое нарушено, и значение-нарушитель;
  • тип подбирайте по смыслу: ValueError — значение, TypeError — тип данных.

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

Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

value = 0
try:
    if value == 0:
        raise ValueError('ноль не принимаем')
    print('принято')
except ValueError as e:
    print('отказ:', e)
print('конец')
value = 7
try:
    if value == 0:
        raise ValueError('ноль не принимаем')
    print('принято:', value)
except ValueError as e:
    print('отказ:', e)
for s in [50, 120]:
    try:
        if s > 100:
            raise ValueError(f'{s} выше лимита')
        print(s, 'в норме')
    except ValueError as e:
        print('пропуск:', e)
Проверь себя
0 / 8

1. Что делает команда raise ValueError('текст')?

2. Выполнятся ли строки кода, написанные после сработавшего raise?

3. Чем для except отличается ваш raise от ошибки, брошенной Python?

4. Что напечатает str(e) после raise ValueError?

5. Случился raise 'строка'. Что произойдёт?

6. Почему печать предупреждения — плохая замена raise?

7. Какой тип правильнее бросить, если вместо числа пришла строка?

8. Зачем в сообщении raise f'оценка {s} больше 100' используют f-строку?

Карточки терминов
Запомнено: 0 / 8
Практика

Дано age = -3. Внутри try проверь правило: если возраст отрицательный, брось ValueError с текстом «возраст не может быть отрицательным». При успехе печатай «Принят возраст: N», при нарушении — «Отклонено: <текст>».

practice.py
Вопросы и ответы по уроку

Как бросить исключение в python вручную?

Командой raise с типом и сообщением: raise ValueError('описание нарушения'). Выполнение остановится на этой строке, а исключение уйдёт в ближайший except или упадёт с traceback, если ловить некому.

Урок 6: else и finally — два хвоста try

Когда стоит бросать исключение самому?

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

Какой тип исключения выбирать для raise?

Стандартный, по смыслу нарушения: ValueError — не подошло значение, TypeError — не подошёл тип данных, KeyError — обязательного не хватает. Текст пишите всегда: он объясняет правило словами, без него сообщение будет пустым.

Можно ли написать raise 'строка с текстом'?

Нет: бросать можно только объекты классов исключений. Python ответит TypeError: exceptions must derive from BaseException. Текст передаётся в скобках: raise ValueError('строка с текстом').

Как обработать собственное исключение?

Как обычное: обернуть проверку в try и написать except с тем же типом. Сообщение попадёт в переменную через as e — его можно напечатать в протокол. Разница между ошибкой Python и вашим raise для обработчика отсутствует.

Понравился урок? Сошлитесь на него

«raise превращает нарушенное правило данных в настоящую ошибку Python — с типом, понятным текстом и traceback.»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Что дальше

Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.