Урок курса

Чтение traceback и типичные ошибки

Python для новичков

В одном из первых уроков вы уже сталкивались с тем, что Python сообщает об ошибке: выводил что-то вроде «File "main.py", line 3» и название ошибки. Тогда речь шла о SyntaxError — проблемах, которые Python замечает ещё до запуска программы. Сейчас мы разбираем другой класс: ошибки времени выполнения. Программа стартует, что-то делает — и в какой-то момент падает с многострочным сообщением. Это сообщение называется traceback, и читать его — отдельный навык.

Структура traceback: что Python печатает при ошибке

Когда программа падает в момент выполнения, Python не просто выводит одну строку. Он печатает полный отчёт — traceback. Выглядит это примерно так:

Traceback (most recent call last):
  File "main.py", line 5, in <module>
    result = calculate(0)
  File "main.py", line 2, in calculate
    return 10 / x
ZeroDivisionError: division by zero

Разберём, из чего это состоит.

Первая строка всегда одна и та же:

Traceback (most recent call last):

Она сигнализирует: дальше идёт стек вызовов. Фраза «most recent call last» подсказывает порядок: внизу будет самый последний вызов — то есть именно то место, где всё сломалось.

Стек вызовов — это последовательность функций, которые были активны в момент ошибки. Каждая функция — один кадр, и Python показывает их по порядку: от точки входа в программу до места, где возникло исключение. Каждый кадр стека состоит из двух составляющих: строки заголовка и фрагмента кода.

Строка заголовка:

  File "main.py", line 2, in calculate

В ней три элемента: имя файла (File "main.py"), номер строки (line 2) и имя функции (in calculate).

Фрагмент кода — строка сразу под заголовком:

    return 10 / x

Это дословная выдержка из исходного файла — именно тот код, который выполнялся в данном кадре.

Если функций в цепочке несколько, кадров будет несколько. Самый нижний кадр — непосредственное место, где Python столкнулся с проблемой.

Последняя строка — это тип исключения и его описание:

ZeroDivisionError: division by zero

До двоеточия — имя класса ошибки (тип исключения). После двоеточия — короткое объяснение от Python. Именно с этой строки начинается диагностика: прочитав тип, уже можно понять природу проблемы, не вникая в весь стек.

Важно понять: traceback — не хаотичный вывод, а структурированный отчёт с фиксированной анатомией. Начало — всегда «Traceback (most recent call last):». Конец — всегда тип исключения. Всё между ними — цепочка вызовов, которая привела к ошибке.

Самостоятельная практика. Проверьте, сможете ли вы по traceback определить место и причину деления на ноль. Разобрать traceback в задаче с проверкой. Если ошибки возникают из-за пробелов в основах, в бесплатном курсе Python есть последовательные уроки и практика с проверкой решений. Начать бесплатный курс Python.

Процедура локализации ошибки по traceback

Зная анатомию traceback, можно выработать устойчивый алгоритм: что читать первым, что — вторым, и где искать ответ на вопрос «что сломалось и где».

Алгоритм выглядит так:

  1. Найти строку Traceback (most recent call last): — она отмечает начало сообщения.

  2. Перейти сразу в конец: прочитать последнюю строку — там тип исключения и его описание. Именно это говорит, что пошло не так.

  3. Подняться на одну строку выше — это последний кадр стека. Он показывает где именно: файл и номер строки.

  4. Открыть указанный файл, перейти к этой строке.

  5. Сопоставить тип ошибки с тем, что написано в коде, и исправить.

Шаги 2 и 3 — самые важные. Всё остальное в стеке — контекст, который нужен только если первопричина не очевидна.

Типичная ловушка: читать traceback сверху вниз

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

Правильное направление — снизу вверх. Последняя строка — это диагноз. Предпоследний кадр — это адрес. Только после того, как прочитаны оба, имеет смысл подниматься выше по стеку, если нужно понять цепочку вызовов.

Вот пример: Python вывел такой traceback:

Traceback (most recent call last):
  File "app.py", line 10, in <module>
    show_result()
  File "app.py", line 6, in show_result
    print(reslt)
NameError: name 'reslt' is not defined

Читаем снизу:

  • NameError: name 'reslt' is not defined — имя не определено.
  • Последний кадр: File "app.py", line 6, in show_result — идём в app.py, строка 6.
  • Видим print(reslt) — опечатка в имени переменной.

В стек выше (line 10, in <module>) заходить не нужно: там просто вызов функции, сама ошибка — внутри неё.

Когда нужно подниматься выше по стеку? Только если в последнем кадре код выглядит корректно сам по себе, и причина ошибки кроется в том, с какими данными его вызвали — то есть проблема возникла раньше, на уровне вызывающего кода. Для большинства ошибок начального уровня достаточно двух нижних строк.

NameError, TypeError, ZeroDivisionError: причины и сообщения

Тип исключения в последней строке traceback — это не просто название. По нему можно сразу предположить причину, ещё до того как откроешь файл с кодом. Разберём три исключения, которые встречаются чаще всего.

NameError

Появляется, когда Python встречает имя, которое ему неизвестно. Самое частое объяснение: опечатка в имени переменной или функции, либо переменная используется раньше, чем ей что-то присвоили.

Сообщение всегда выглядит так:

NameError: name 'reslt' is not defined

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

Важный нюанс: Python не проверяет имена заранее при запуске. Он доходит до строки с неизвестным именем в момент выполнения — и только тогда бросает NameError. Поэтому ошибка может появиться в середине работы программы, а не сразу.

TypeError

Появляется, когда операция несовместима с типами участвующих значений. Самый классический сценарий — попытка соединить строку и число через +:

TypeError: can only concatenate str (not "int") to str

По сообщению сразу понятно: Python ожидал строку, а получил int. Другой распространённый вариант — передать в функцию аргумент не того типа, который она ожидает.

Отличительная черта TypeError: Python не догадывается о намерении. Если написано 'Возраст: ' + 25, он не пытается автоматически привести 25 к строке — он останавливается и сообщает о конфликте типов.

ZeroDivisionError

Появляется ровно в одном случае: делитель оказался равен нулю. Не важно, откуда взялся ноль — из переменной, из вычисления, из ввода пользователя. Как только Python вычисляет выражение с / или // и видит ноль в знаменателе — бросает исключение:

ZeroDivisionError: division by zero

Сообщение здесь всегда одинаковое и не содержит лишних деталей. Всю информацию о где даёт кадр стека над ним.

Важный момент: ошибка возникает в момент вычисления, а не когда переменная получает значение 0. То есть y = 0 само по себе не падает — падает x / y на следующей строке.


Каждый из трёх типов говорит о принципиально разной проблеме:

  • NameError → неизвестное имя (опечатка или порядок выполнения)
  • TypeError → конфликт типов в операции
  • ZeroDivisionError → арифметически недопустимое действие

Этот словарь работает в обе стороны: читая traceback, ты по типу исключения сразу знаешь, что искать в коде.

Воспроизведение и исправление ошибок на примерах

Пройдём полный цикл для каждого из трёх исключений: ошибочный код → traceback → исправление.

NameError: переменная используется до присваивания

print(score)
score = 100

Python выведет:

Traceback (most recent call last):
  File "main.py", line 1, in <module>
    print(score)
NameError: name 'score' is not defined

Читаем снизу: NameError: name 'score' is not defined — имя score Python не знает. Кадр стека: line 1. Смотрим на код: переменная score там есть, она написана правильно — значит, дело не в опечатке. Проблема в порядке: print(score) стоит раньше, чем score = 100. Python выполняет строки сверху вниз и, когда доходит до print(score), присваивание ещё не произошло. Исправление — поменять строки местами:

score = 100
print(score)  # сначала присваивание, потом использование

Программа выводит 100 без ошибок.

Вариация: NameError с той же последней строкой traceback возникает и при опечатке в имени (print(reslt) вместо print(result)). Тогда имя в кавычках сообщения отличается от имени переменной в коде — это сразу подсказывает, что искать опечатку, а не переставлять строки.


TypeError: строка плюс число

age = 25
print('Возраст: ' + age)

Python выведет:

Traceback (most recent call last):
  File "main.py", line 2, in <module>
    print('Возраст: ' + age)
TypeError: can only concatenate str (not "int") to str

Последняя строка сразу говорит: операция + ожидала строку, но получила int. Кадр стека указывает на line 2. Там 'Возраст: ' + age — строку и целое число нельзя складывать напрямую. Два равнозначных способа исправить:

age = 25

# Вариант 1: явное приведение типа
print('Возраст: ' + str(age))

# Вариант 2: f-строка
print(f'Возраст: {age}')

Оба варианта выведут Возраст: 25. F-строка читается чище, особенно когда переменных несколько.


ZeroDivisionError: деление на ноль

x = 10
y = 0
print(x / y)

Python выведет:

Traceback (most recent call last):
  File "main.py", line 3, in <module>
    print(x / y)
ZeroDivisionError: division by zero

Последняя строка однозначна. Кадр стека: line 3, выражение x / y. Значение y равно нулю — это и есть проблема. Исправление: проверить делитель перед делением.

x = 10
y = 0

if y != 0:
    print(x / y)
else:
    print('Делить на ноль нельзя')

Теперь программа не падает: она проверяет y заранее и выводит понятное сообщение вместо traceback.


Во всех трёх случаях цикл одинаковый: читаем последнюю строку traceback → находим кадр с номером строки → смотрим на код → исправляем конкретную проблему. Тип исключения каждый раз подсказывал, в какую сторону смотреть: порядок выполнения или опечатка при NameError, конфликт типов при TypeError, нулевой делитель при ZeroDivisionError. В следующем уроке эти же типы исключений можно будет перехватывать блоком try-except — и тогда программа сможет обрабатывать ошибки, не прерывая работу.

Задача 1

Посмотрите на traceback:

Traceback (most recent call last):
 File "calc.py", line 5, in <module>
 result = total / count
ZeroDivisionError: division by zero

Что можно точно установить из этого сообщения?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 2

Дан traceback:

Traceback (most recent call last):
 File "app.py", line 3, in <module>
 greet(usernme)
NameError: name 'usernme' is not defined

Какое исправление устранит ошибку?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 3

Код завершается с TypeError, потому что складывает строку и число:

age = 25
message = 'Возраст: ' + age

Выберите все варианты, которые исправляют вторую строку.

Выберите все подходящие варианты
Без регистрации · результат не сохраняется

Задача 4

Начинающий программист видит многострочный traceback и начинает читать его с первой строки. Почему такой подход часто не помогает быстро найти ошибку?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 5

Исправь имя переменной в выводе отчёта

В файле уже есть код для короткого отчёта о пользователе. При запуске он падает с traceback и ошибкой NameError.

Исправьте только опечатку в имени переменной так, чтобы программа вывела одну строку:

Пользователь: Аня, баллы: 18

Ничего лишнего печатать не нужно. Смысл задания — прочитать traceback, найти строку с ошибкой и исправить имя в коде.

РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Задача 6

Исправь вывод суммы заказа

В стартовом коде программа должна вывести сообщение о заказе, но сейчас она падает с TypeError.

Исправьте код так, чтобы программа печатала одну строку в таком виде:

Заказ № 17: сумма 850 руб.

Подсказка: в сообщении есть число, а к строке число напрямую складывать нельзя. Нужно исправить именно сборку строки, а не менять сами данные.

РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Задачи к уроку

Все задачи курса →

Продолжить с сохранением прогресса

Перейдите к уроку в учебном кабинете.

Перейти к интерактивному уроку