Try except в Python: как обработать ошибку и не уронить программу

Конструкция try except перехватывает ошибку, и программа на Python продолжает работу вместо падения с трейсбеком.

На 13 запущенных примерах показываем, как ловить несколько исключений, когда срабатывают else и finally, как вызвать своё исключение через raise и почему голый except прячет баги.

Статью написал:
Ваня Буявец, продюсер, основатель Checkroi
Ваня Буявец
Основатель Checkroi, продюсер, эксперт в выборе онлайн-курсов
Все 3139 статей автора Подписаться на Телеграм-канал
Одобрено экспертом:
Наташа Буявец, основатель Checkroi, эксперт по онлайн-курсам
Наташа Буявец
Основательница Checkroi, продюсер Youtube-каналов, эксперт по онлайн-курсам
Все 3793 экспертных мнения Подписаться на Телеграм-канал
Обложка: Try except в Python: как обработать ошибку и не уронить программу

Чтобы программа на Python не падала от ошибки, оберните опасную строку в try, а реакцию на сбой напишите в except: try: number = int(text), ниже except ValueError: print("Это не число"). Если в блоке try возникло исключение нужного типа, Python выполнит код из except и продолжит работу. Блок else сработает, когда ошибок не было, а finally выполнится в любом случае.

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

CheckroiCheckroiПодборка курсов по Python569 курсов • 52 школыСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

Как работает try except в Python

Рой ловит ошибку в коде сачком

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

number = int("12a")
print("Эта строка не выполнится")

Результат:

Traceback (most recent call last):
  File "main.py", line 1, in <module>
    number = int("12a")
ValueError: invalid literal for int() with base 10: '12a'

Самая полезная строка трейсбека последняя: в ней тип исключения (ValueError) и пояснение. Именно этот тип и пишут после except.

Порядок работы конструкции такой:

  1. Python выполняет строки внутри try одну за другой.
  2. Если ошибок нет, блок except пропускается целиком.
  3. Если на какой-то строке возникло исключение, остаток try не выполняется.
  4. Python ищет первый except, чей тип подходит к ошибке, и запускает его код.
  5. Если подходящего except нет, исключение уходит выше, в вызывающий код, а оттуда может уронить всю программу.

Тот же пример с обработкой:

text = "12a"
try:
    number = int(text)
except ValueError:
    print("Это не целое число:", text)

Результат:

Это не целое число: 12a

Чаще всего так защищают ввод с клавиатуры. Как проверять число от пользователя без падений, мы подробно разобрали в статье про int(input()).

Несколько except и переменная as e

Одна строка может сломаться по разным причинам. Под каждую причину заводят свой except, а через as e получают сам объект ошибки с текстом:

def safe_div(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        print("На ноль делить нельзя")
        return None
    except TypeError as e:
        print("Неверный тип:", e)
        return None

print(safe_div(10, 4))
print(safe_div(10, 0))
print(safe_div(10, "2"))

Результат:

2.5
На ноль делить нельзя
None
Неверный тип: unsupported operand type(s) for /: 'int' and 'str'
None

Python проверяет блоки except сверху вниз и запускает первый подходящий. Поэтому частные типы ставят выше общих: если первым написать except Exception, до ZeroDivisionError дело не дойдёт никогда.

Один обработчик на два типа

Когда реакция на разные ошибки одинаковая, типы перечисляют в скобках:

data = {"price": "990"}

for key in ("price", "discount"):
    try:
        value = int(data[key])
    except (KeyError, ValueError) as e:
        print("Пропускаем", key, "из-за", type(e).__name__)
    else:
        print(key, "=", value)

Результат:

price = 990
Пропускаем discount из-за KeyError

С версии 3.14 скобки можно опустить, если после типов не стоит as. Это описано в списке изменений Python 3.14 (PEP 758):

items = ["10", "x", "0"]

for item in items:
    try:
        result = 100 / int(item)
    except ValueError, ZeroDivisionError:
        print(item, "→ не подходит")

Результат:

x → не подходит
0 → не подходит

В Python 3.13 и более ранних версиях та же запись даст SyntaxError. Если код запускают на разных версиях, оставляйте скобки.

Канал основателя Checkroi Вани Буявца3 700 человек читают мой Телеграм-канал про нейросетиСобрал промпты для Claude Code и ChatGPT, разборы ИИ-инструментов и лайфхаки по продвижению бизнеса в одном местеПрисоединиться

Блоки else и finally

Три отсека: попытка, перехват, завершение

У try except есть два необязательных блока. Они пишутся после всех except, сначала else, потом finally.

Этот else относится к try и с ветвлением if не связан. Условия в одну строку устроены по-другому, о них мы писали в статье про тернарный оператор.

Блок Когда выполняется Зачем нужен
try всегда, первым код, который может упасть
except если в try возникло исключение подходящего типа реакция на ошибку
else если в try ошибок не было продолжение удачного сценария
finally всегда, последним, даже после return закрыть файл, соединение, снять блокировку

Посмотрим порядок на функции, которая возвращает значение из разных блоков:

def read_number(text):
    print("try: начинаем")
    try:
        value = int(text)
    except ValueError:
        print("except: ошибка в данных")
        return None
    else:
        print("else: ошибок не было")
        return value
    finally:
        print("finally: выполняется всегда")

print(read_number("42"))
print("---")
print(read_number("сорок два"))

Результат:

try: начинаем
else: ошибок не было
finally: выполняется всегда
42
---
try: начинаем
except: ошибка в данных
finally: выполняется всегда
None

Видно, что finally отработал раньше, чем функция вернула результат, причём в обоих случаях.

Зачем выносить код в else, если его можно дописать в конец try? Учебник на docs.python.org отвечает так: блок else лучше, потому что не даёт случайно перехватить исключение из кода, который вы защищать не собирались. В try остаётся только опасная строка, всё остальное идёт ниже.

Для файлов вместо try finally обычно пишут with open(...): менеджер контекста закроет файл сам, даже если внутри случится ошибка. Как это выглядит, показали в инструкции о том, как открыть файл в Python.

CheckroiCheckroiПодборка курсов для Python-разработчиков85 курсов • 33 школыСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

Какие исключения встречаются чаще всего

Все встроенные исключения выстроены в дерево. В корне стоит BaseException, от него наследуется Exception, а уже от него почти все ошибки, с которыми вы будете работать. Полное дерево лежит в справке по встроенным исключениям.

Исключение Код, который его вызывает Что случилось
ValueError int("abc") тип подходит, значение нет
TypeError "5" + 3 операция не работает с таким типом
KeyError {"a": 1}["b"] в словаре нет такого ключа
IndexError [1, 2][5] индекс за пределами списка
ZeroDivisionError 10 / 0 деление на ноль
FileNotFoundError open("nofile.txt") файла нет по указанному пути
AttributeError "текст".push("x") у объекта нет такого метода
NameError print(undefined_name) переменная не объявлена или опечатка
ModuleNotFoundError import no_such_module_xyz библиотека не установлена в окружение

Деление на ноль чаще всего ловят в арифметике с вводом пользователя. Чем отличаются /, // и % и когда каждый из них падает, мы показали в статье про остаток от деления.

Наследование работает и в except. KeyError и IndexError происходят от LookupError, поэтому except LookupError поймает обе ошибки. FileNotFoundError наследуется от OSError, а ModuleNotFoundError от ImportError.

Две ошибки стоят особняком: KeyboardInterrupt (нажали Ctrl+C) и SystemExit (вызвали sys.exit()) наследуются прямо от BaseException, минуя Exception. Поэтому except Exception их пропускает, и программу по-прежнему можно остановить с клавиатуры.

Многие из этих ошибок проще предотвратить, чем ловить. KeyError обходят методом get() у словаря, а ModuleNotFoundError часто значит, что библиотеку поставили не в то виртуальное окружение.

Как вызвать исключение самому: raise

Рой уверенно запускает свою проверку

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

Свой класс исключения

Своё исключение пишется как обычный класс, унаследованный от Exception или от подходящего встроенного типа. Если про классы пока ничего не знаете, загляните в разбор ООП простыми словами.

class NegativeAgeError(ValueError):
    pass

def set_age(age):
    if age < 0:
        raise NegativeAgeError(f"возраст не может быть отрицательным: {age}")
    return age

try:
    set_age(-5)
except NegativeAgeError as e:
    print("Ошибка:", e)

Результат:

Ошибка: возраст не может быть отрицательным: -5

Раз NegativeAgeError наследуется от ValueError, вызывающий код может ловить её и общим except ValueError.

raise from: одна ошибка как причина другой

Когда вы ловите низкоуровневую ошибку и бросаете свою, понятную, добавьте from e. Python покажет обе ошибки и свяжет их:

import json

def load_config(text):
    try:
        return json.loads(text)
    except json.JSONDecodeError as e:
        raise ValueError("конфиг повреждён") from e

load_config("{name: 1}")

Последние строки трейсбека:

json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "main.py", line 9, in <module>
    load_config("{name: 1}")
    ~~~~~~~~~~~^^^^^^^^^^^^^
  File "main.py", line 7, in load_config
    raise ValueError("конфиг повреждён") from e
ValueError: конфиг повреждён

Повтор ввода до правильного ответа

raise внутри try удобно сочетать с циклом. Здесь программа перебирает ответы, пока не найдёт целое положительное число. Список ответов заменяет input(), чтобы пример запускался без клавиатуры:

answers = ["пять", "-3", "7"]

for raw in answers:
    try:
        n = int(raw)
        if n < 0:
            raise ValueError("число меньше нуля")
    except ValueError as e:
        print(f"{raw!r}: введите целое положительное число ({e})")
        continue
    print("Принято:", n)
    break

Результат:

'пять': введите целое положительное число (invalid literal for int() with base 10: 'пять')
'-3': введите целое положительное число (число меньше нуля)
Принято: 7

В реальной программе вместо for ставят цикл while True с input(), а выходят из него через break.

CheckroiCheckroiПодборка курсов по Python464 курса • 49 школСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

Частые ошибки и что с ними делать

Голый except без типа

Симптом: программа перестаёт реагировать на Ctrl+C, а настоящие баги исчезают без следа.

Причина в том, что except: без типа ловит вообще всё, включая KeyboardInterrupt и SystemExit. В руководстве по стилю PEP 8 об этом сказано прямо: такой блок мешает прервать программу с клавиатуры и может скрыть другие проблемы.

Решение: указывайте конкретный тип. Если нужно поймать любую ошибку программы, пишите except Exception.

Слишком много кода в try

Симптом: обработчик срабатывает «не на ту» ошибку. В примере ниже цена есть, но программа сообщает обратное:

prices = {"курс": 990}

try:
    total = prices["курс"] * 2
    print("Итого:", totl)
except Exception:
    print("Не нашли цену")

Результат:

Не нашли цену

На самом деле упал NameError из-за опечатки в totl, а общий except выдал его за отсутствие ключа.

Решение: оставьте в try одну опасную строку, ловите конкретный KeyError, а остальное переносите в else.

SyntaxError: expected ‘except’ or ‘finally’ block

Симптом: программа не запускается вообще.

try:
    x = 1
print(x)

Результат:

  File "main.py", line 3
    print(x)
    ^^^^^
SyntaxError: expected 'except' or 'finally' block

Причина: у try обязан быть хотя бы один except или finally, а здесь блок оборвался. Та же ошибка появляется, когда except съехал левее своего try, например на уровень внешнего if.

Решение: допишите обработчик на том же уровне отступа, что и try.

return внутри finally

Симптом: функция возвращает не то, что вы ждали, а исключения пропадают.

def check():
    try:
        return "из try"
    finally:
        return "из finally"

print(check())

Результат:

main.py:5: SyntaxWarning: 'return' in a 'finally' block
  return "из finally"
из finally

return в finally перебивает значение из try и гасит любое исключение. С версии 3.14 Python выдаёт на такой код предупреждение (PEP 765).

Решение: в finally только освобождайте ресурсы, а результат возвращайте из try или else. Как return работает в обычной функции, разобрано в инструкции про функции в Python.

Ошибку поймали и забыли

Блок except: pass прячет сбой так, что потом его не найти. Если ошибку нельзя исправить на месте, хотя бы запишите её в лог вместе с трейсбеком:

import logging

logging.basicConfig(level=logging.ERROR, format="%(levelname)s %(message)s")

try:
    1 / 0
except ZeroDivisionError:
    logging.exception("Сбой при расчёте")

Результат:

ERROR Сбой при расчёте
Traceback (most recent call last):
  File "main.py", line 6, in <module>
    1 / 0
    ~~^~~
ZeroDivisionError: division by zero

И последнее, о чём спрашивают те, кто пришёл из Java или JavaScript: в Python нет try catch. Ту же роль играет except, а строка catch Exception: после try даст уже знакомую SyntaxError: expected 'except' or 'finally' block.

Ваня БуявецКанал основателя Checkroi Вани БуявцаЗабирайте промпты и обучение по нейросетям в моём Телеграм-каналеБольше 3 700 человек уже применяют Claude Code, ChatGPT и другие нейросети в работе, учёбе, бизнесе и жизниПерейти в канал

Где освоить Python системно

Без обработки исключений не обходится ни одна рабочая программа, которая читает файлы, ходит в сеть или принимает ввод пользователя. Если хотите пройти Python по порядку, от основ до своих проектов, с наставником и проверкой домашних заданий, сравните курсы в нашем каталоге. Начать с азов можно и с подборки основных команд Python.

КурсШколаСтоимость со скидкойВ рассрочкуДлитель­ностьОбзор курса от Checkroi
Профессия «Python-разработчик»
Перейти на сайт курса
SkillboxSkillbox157 335 ₽5987 ₽/мес.10 месяцевОбзор курса
Fullstack-разработчик на Python
Перейти на сайт курса
НетологияНетология137 000 ₽7125 ₽/мес.21 месяцОбзор курса
ДО Профессия Python-разработчик
Перейти на сайт курса
GeekBrainsGeekBrains149 001 ₽3167 ₽/мес.10 месяцевОбзор курса
Автоматизированное тестирование на Python
Перейти на сайт курса
SkillboxSkillbox122 226 ₽4108 ₽/мес.9 месяцевОбзор курса
Профессия Python-разработчик
Перейти на сайт курса
SkillFactorySkillFactory140 040 ₽3890 ₽/мес.10 месяцевОбзор курса

Больше программ — в полном каталоге курсов по Python

Часто задаваемые вопросы

Что делает try в Python?

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

Есть ли в Python try catch?

Нет, ошибку перехватывает только except. Строка catch Exception: после try даст SyntaxError: expected 'except' or 'finally' block.

Когда выполняется else в try except?

Только если в try не было исключения. Туда переносят код, который идёт после опасной строки, чтобы случайно не перехватить его собственные ошибки.

Выполнится ли finally, если в try стоит return?

Да, finally срабатывает последним в любом случае, даже перед return. А return внутри самого finally перебьёт результат, и с версии 3.14 Python предупреждает об этом через SyntaxWarning.

Как поймать несколько исключений одним except?

Перечислите типы в скобках: except (KeyError, ValueError) as e. С Python 3.14 скобки можно не ставить, если после типов нет as.

Как вызвать исключение вручную?

Оператором raise, например raise ValueError("возраст меньше нуля"). Для своих ошибок создайте класс, унаследованный от Exception или от подходящего встроенного типа.

Читайте Checkroi первым в Google
Добавьте Checkroi в избранные источники — и наши разборы курсов и обзоры школ будут показываться выше в вашей выдаче Google.
Оставить комментарий
0 комментариев
Форма комментария

Оставьте комментарий

Напишите, что думаете. Нам важно ваше мнение!