Чтобы программа на Python не падала от ошибки, оберните опасную строку в try, а реакцию на сбой напишите в except: try: number = int(text), ниже except ValueError: print("Это не число"). Если в блоке try возникло исключение нужного типа, Python выполнит код из except и продолжит работу. Блок else сработает, когда ошибок не было, а finally выполнится в любом случае.
Ниже разберём, как устроена конструкция try except, какие исключения встречаются чаще всего и где новички ошибаются. Если отступы и двоеточия в Python ещё путаются, начните с короткой статьи про синтаксис Python.
Как работает 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.
Порядок работы конструкции такой:
- Python выполняет строки внутри
tryодну за другой. - Если ошибок нет, блок
exceptпропускается целиком. - Если на какой-то строке возникло исключение, остаток
tryне выполняется. - Python ищет первый
except, чей тип подходит к ошибке, и запускает его код. - Если подходящего
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. Если код запускают на разных версиях, оставляйте скобки.
Блоки 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.
Какие исключения встречаются чаще всего
Все встроенные исключения выстроены в дерево. В корне стоит 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.
Частые ошибки и что с ними делать
Голый 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.
Где освоить Python системно
Без обработки исключений не обходится ни одна рабочая программа, которая читает файлы, ходит в сеть или принимает ввод пользователя. Если хотите пройти Python по порядку, от основ до своих проектов, с наставником и проверкой домашних заданий, сравните курсы в нашем каталоге. Начать с азов можно и с подборки основных команд Python.
| Курс | Школа | Стоимость со скидкой | В рассрочку | Длительность | Обзор курса от Checkroi |
|---|---|---|---|---|---|
| Профессия «Python-разработчик» Перейти на сайт курса | 157 335 ₽ | 5987 ₽/мес. | 10 месяцев | Обзор курса | |
| Fullstack-разработчик на Python Перейти на сайт курса | 137 000 ₽ | 7125 ₽/мес. | 21 месяц | Обзор курса | |
| ДО Профессия Python-разработчик Перейти на сайт курса | 149 001 ₽ | 3167 ₽/мес. | 10 месяцев | Обзор курса | |
| Автоматизированное тестирование на Python Перейти на сайт курса | 122 226 ₽ | 4108 ₽/мес. | 9 месяцев | Обзор курса | |
| Профессия Python-разработчик Перейти на сайт курса | 140 040 ₽ | 3890 ₽/мес. | 10 месяцев | Обзор курса |
Больше программ — в полном каталоге курсов по Python




