Что такое исключение: первая ошибка в программе
Первая ошибка в программе: читаем traceback за десять секунд — тип ошибки, место и сообщение. Разбираем четыре типовых падения на живом коде.
Редакция Питоники
Программы падают — и это нормально. Плохо другое: когда программист видит красный текст на английском и пугается, вместо того чтобы прочитать его за десять секунд. В этом уроке мы специально уроним программу несколько раз и каждый раз разберём отчёт об ошибке по косточкам. Исключение — не приговор, а сообщение с именем: у него есть тип, место и текст. Научившись их читать, вы перестанете бояться traceback и начнёте использовать его как инструмент.
Программа выполняется строка за строкой
Python читает программу сверху вниз и выполняет строки по одной. Пока каждая строка срабатывает, выполнение доходит до конца файла:
prices = [100, 250, 80]
print('Товаров:', len(prices))
print('Сумма:', prices[0] + prices[1] + prices[2])
Товаров: 3 Сумма: 430
Три строки, три действия, программа дошла до конца. Но стоит одной строке столкнуться с невозможной операцией — и выполнение останавливается прямо на ней. Всё, что написано ниже, не выполнится: Python не угадывает, как продолжать, когда операция невозможна. Вместо этого он печатает отчёт об ошибке — traceback.
Первая авария: разбор строки в число
Возьмём частую операцию — превращение текста в число. Функция int принимает строку с цифрами и возвращает целое число. Пробелы по краям она терпит, минус понимает:
print(int('18'))
print(int('0'))
print(int(' 7 '))
print(int('-7'))
18 0 7 -7
А теперь подсунем int слово вместо числа. Слово «двенадцать» — это текст, но не числовой текст: цифр в нём нет. Операция невозможна, и Python реагирует отчётом:
n = int('двенадцать')
print('Разобрали:', n)
Traceback (most recent call last):
File "app.py", line 1, in <module>
n = int('двенадцать')
~~~^^^^^^^^^^^^^^
ValueError: invalid literal for int() with base 10: 'двенадцать'Разбираем отчёт построчно, снизу вверх — именно так его и читают. Последняя строка traceback — тип ошибки и её сообщение: читать traceback начинают именно с неё. Тип здесь — ValueError, «ошибка значения»: сама операция существует, но значение неподходящее. Сообщение поясняет: invalid literal for int() with base 10 — «текст нельзя разобрать как целое число». Строки выше показывают место: файл app.py, строка 1, и саму строку кода с каретками под виновником. Заголовок Traceback (most recent call last) сообщает, что ниже — цепочка вызовов, где последнее место — то, где всё сломалось. Пока у нас один уровень, но в больших программах по нему виден весь путь до аварии.
total = 100
participants = 0
print('Делим сумму на участников')
print(total / participants)
Делим сумму на участников
Traceback (most recent call last):
File "app.py", line 4, in <module>
print(total / participants)
~~~~~~^~~~~~~~~~~~~~
ZeroDivisionError: division by zeroОбратите внимание: две строки до аварии напечатались, а авария случилась на четвёртой. Traceback всегда указывает точную строку, на которой выполнение остановилось, — всё до неё уже сработало, всё после неё не начнётся. Тип ZeroDivisionError говорит сам за себя: делить на ноль нельзя, и Python отказывается притворяться, что можно.
price = '3'
count = 3
total = price + count
print('Итого:', total)
Traceback (most recent call last):
File "app.py", line 3, in <module>
total = price + count
~~~~~~^~~~~~~
TypeError: can only concatenate str (not "int") to strТут причина другая. Сложение существует и для строк, и для чисел, но Python не складывает строку с числом: типы не совпали. Отсюда и имя — TypeError, ошибка типа. Сообщение расшифровывается так: «строку можно соединить только со строкой, а не с int». Кстати, проверять типы значений можно функцией type — она печатает класс, к которому относится значение:
print(type(18))
print(type('18'))
print(type(3.5))
<class 'int'> <class 'str'> <class 'float'>
Таблица типовых падений
Большинство аварий новичка укладываются в семь типов. Сохраните таблицу: чтение traceback начинается с последней строки, и узнать тип — значит понять половину причины.
| Тип | Когда случается | Пример |
|---|---|---|
| ValueError | Операция верная, значение неподходящее | int('двенадцать') |
| TypeError | Операция не применима к таким типам | '3' + 3 |
| ZeroDivisionError | Деление на ноль | 100 / 0 |
| NameError | Имя не найдено: опечатка или забыли создать | print(totl) |
| KeyError | Ключа нет в словаре | guests['Вера'] |
| IndexError | Индекса нет в списке | items[10] |
| SyntaxError | Код написан не по правилам языка | print('привет' |
Место ошибки: файл, строка, цепочка
Средние строки traceback отвечают на вопрос «где». Запись File "app.py", line 2, in <module> читается так: файл app.py, строка 2, на верхнем уровне программы (не внутри функции — тогда вместо <module> стояло бы её имя). Под ней печатается сама строка кода с каретками под точным местом аварии. Посмотрим на NameError — типичную опечатку в имени:
orders = 12
print('Заказов:', totl)
Traceback (most recent call last):
File "app.py", line 2, in <module>
print('Заказов:', totl)
^^^^
NameError: name 'totl' is not definedСообщения NameError звучат обидно понятно: name 'totl' is not defined — «имя totl не определено». В девяти случаях из десяти это опечатка: переменная orders объявлена, а печатаем мы несуществующий totl. Traceback подсвечивает каретками само имя — чинится за секунду.
guests = {'Анна': 2, 'Борис': 1}
print('Вера приходила:', guests['Вера'])
print('Конец программы')
Traceback (most recent call last):
File "app.py", line 2, in <module>
print('Вера приходила:', guests['Вера'])
~~~~~~^^^^^^^^
KeyError: 'Вера'Ключ в сообщении печатается в кавычках — Python показывает, какого именно ключа не хватило. А строка «Конец программы» так и не напечаталась: это лучшая демонстрация того, что исключение останавливает программу. Всё, что написано ниже аварийной строки, мертво, пока ошибка не обработана. Обработка — тема следующего урока, а пока закрепим главный навык этого.
guests = {'Анна': 2, 'Борис': 1, 'Вера': 3}
print('Вера приходила:', guests['Вера'])
print('Конец программы')
Вера приходила: 3 Конец программы
Проверка заранее: ключ есть или нет
У KeyError есть и мирный путь — проверить ключ заранее оператором in. Это не обработка ошибки, а профилактика, и для одного словаря она читается легко:
guests = {'Анна': 2, 'Борис': 1}
name = 'Вера'
if name in guests:
print(name, 'приходила:', guests[name])
else:
print(name, 'не приходила')
Вера не приходила
Для одного-двух ключей профилактика хороша. Когда данных много, проверка каждой строки раздувает код — и тогда на сцену выходит запасной план: try и except из следующего урока.
Алгоритм чтения traceback
Соберём навык урока в три шага. Он работает для любой аварии — от первой опечатки до чужой библиотеки.
- прочитать последнюю строку: тип ошибки и сообщение — что сломалось;
- найти своё имя файла в цепочке вызовов и номер строки — где сломалось;
- посмотреть на строку кода с каретками — на чём именно сломалось.
Типы из таблицы мы будем ловить и обрабатывать: в уроке про try и except программа научится переживать аварию вместо падения, а в уроке про except ValueError мы уточним обработчик до конкретного типа. Словари и их KeyError разобраны в первом уроке курса про словари — там же есть способ проверять ключ заранее.
Исключение — это сообщение с именем типа, местом и текстом, и теперь вы умеете его читать. Дальше — научиться на такие сообщения отвечать: не падать, а переключаться на запасной план.
Сначала предскажи ответ в голове — это главный навык программиста.
print('Начало')
numbers = [10, 20, 30]
print(numbers[1])
print(numbers[5])
print(int(' 15 '))
print(int('15 кг'))
x = 5
y = 0
print('Ответ:', x / y)
print('Конец')
1. С какой строки traceback принято начинать чтение?
2. Что означает тип ошибки ValueError в traceback?
3. Программа упала на строке 4. Выполнятся ли строки 5 и дальше?
4. Что означает запись File "app.py", line 2, in <module> в traceback?
5. Какая ошибка возникнет у print(guests['Вера']), если ключа Вера в словаре нет?
6. total = '3' + 3 упал с TypeError. Что означает этот тип?
7. Чем SyntaxError отличается от ValueError и TypeError?
8. Программа напечатала «Делим сумму на участников» и упала на следующей строке. Что это говорит о порядке выполнения?
Дана строка n_str = '50'. Преврати её в число, умножь на 2 и напечатай в формате «50 * 2 = 100» — одним print с f-строкой.
Что такое исключение в Python простыми словами?
Это объект-ошибка, который Python создаёт, когда операция невозможна: деление на ноль, разбор слова как числа, обращение к отсутствующему ключу. Программа останавливается на месте аварии и печатает traceback — отчёт с типом ошибки, местом и сообщением.
Урок 2: try и except — ловим ошибкуКак быстро прочитать traceback?
Начните с последней строки: тип ошибки и сообщение говорят, что сломалось. Затем найдите в средней части своё имя файла и номер строки — где сломалось. Строка кода с каретками под ними покажет точного виновника.
Чем ValueError отличается от TypeError?
ValueError — операция верная, но значение неподходящее: int('двенадцать') умеет разбирать текст в число, но слова с цифрами не содержат. TypeError — сама операция не применима к таким типам: '3' + 3 пытается сложить строку с числом.
Урок 3: except ValueError — ловим конкретный типПочему Python останавливает программу при ошибке?
Потому что продолжать с невыполненной операцией невозможно: у аварийной строки нет результата, и всё дальнейшее опиралось бы на пустоту. Громкое падение с traceback честнее тихой порчи данных — а поймать ошибку и продолжить работу можно через try и except.
Что означает in <module> в traceback?
Это уровень, на котором выполнялся упавший код. in <module> — верхний уровень файла, не внутри функции. Когда авария случится в функции, вместо <module> появится её имя, а в цепочке будет несколько строк — по одной на каждый уровень вызова.
Понравился урок? Сошлитесь на него
«Последняя строка traceback — тип ошибки и её сообщение: читать traceback начинают именно с неё.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Исключения · Урок 2
try и except: ловим ошибку и не падаем
Первый запасной план: try держит рискованный код, except — что делать, если он упал. Прыжки, пропуски и try внутри цикла — на живом коде.
Исключения · Урок 3
except ValueError: ловим конкретный тип ошибки
Уточняем обработчик: except ValueError ловит только свой тип ошибок. Почему голый except прячет опечатки и как ValueError ведёт себя у int и list.remove.
Словари · Урок 1
Словарь в Python: ключ и значение
Словарь — структура «ключ — значение»: достаём номер телефона по имени из телефонной книги, сравниваем dict со списком на живых данных и заглядываем под капот — как Python находит значение по ключу.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
pytest · Урок 9
Проверка исключений: pytest.raises
Хорошая функция на плохом входе не молчит, а бросает исключение — и тест обязан это проверять. pytest.raises делает это одной строкой внутри with.
pytest.raises проверка исключенийpytest проверка исключения
asyncio · Урок 11
Исключения в конкурентном коде
Одна корутина с ValueError способна уронить весь gather. Флаг return_exceptions=True превращает исключения в значения списка — пачка выживает, а отчёт собирается целиком.
asyncio исключения gathergather обработка ошибок
Исключения · Урок 7
raise: бросаем исключение сами
До сих пор ошибки бросал Python. Теперь научимся бросать сами: raise ValueError с понятным текстом, когда данные нарушают правила программы.
raise valueerror pythonpython бросить исключение