Menu
Русский
Попробовать в Playground

Типы ошибок Python и отладка: чтение трейсбэков и исправление частых ошибок

Обзор ошибок Python, которые встретишь чаще всего — KeyError, ValueError, ModuleNotFoundError, EOFError — и привычки отладки, быстро их чинящие.

Ошибки — это способ Python рассказать, что случилось

Каждая ошибка Python — это объект с типом, сообщением и трейсбэком — цепочкой вызовов, приведших к ней. Умение хорошо её читать — главный отладочный навык, который ты можешь развить. Эта страница — обзор ошибок, которые ты реально встретишь, и привычек, которые быстро их чинят.

Глубже про механику try/except и собственный raiseстраница про исключения. Здесь — о конкретных ошибках и чтении их сообщений.

Читаем трейсбэк

Запусти что-то ломающееся:

def divide(a, b):
    return a / b

def report(values):
    for v in values:
        print(divide(10, v))

report([5, 2, 0])

Python распечатает нечто вроде:

Traceback (most recent call last):
  File "script.py", line 8, in <module>
    report([5, 2, 0])
  File "script.py", line 6, in report
    print(divide(10, v))
  File "script.py", line 2, in divide
    return a / b
ZeroDivisionError: division by zero

Читаем снизу вверх:

  1. ZeroDivisionError: division by zero — тип исключения и сообщение. Это что пошло не так.
  2. return a / b в divide, строка 2 — строка, которая реально подняла ошибку.
  3. print(divide(10, v)) в report, строка 6 — вызов, вызвавший ошибку.
  4. report([5, 2, 0]) на уровне модуля, строка 8 — откуда началось.

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

Ошибки, которые встретишь чаще всего

NameError

main.py
Output
Click Run to see the output here.

«Name 'mesage' is not defined». Опечатка или использование переменной до присваивания. На свежих версиях Python обычно подсказывает подходящее имя («Did you mean 'message'?»).

Ремонт: проверь написание и область видимости. Если имя существует только внутри функции, снаружи его не прочесть.

TypeError

main.py
Output
Click Run to see the output here.

«Can only concatenate str (not 'int') to str». Не тот тип для операции. Классика: сложить строку с числом, вызвать что-то невызываемое, передать в функцию не то число аргументов.

Ремонт: явное преобразование типов (str(30), int("30")) или разбор того, что ты реально передал. f-строка обычно читается лучше, чем +-конкатенация разных типов: f"age: {30}".

ValueError

main.py
Output
Click Run to see the output here.

«Invalid literal for int() with base 10: 'hello'». Тип правильный — int() принимает строку, — но значение не годится. Частое у int(), float(), разбора datetime и функций с ограниченным диапазоном аргумента.

Ремонт: валидируй до преобразования или лови ошибку:

main.py
Output
Click Run to see the output here.

KeyError

main.py
Output
Click Run to see the output here.

«KeyError: 'charlie'». Ключа в словаре нет. Три идиоматических ремонта, под разные намерения:

main.py
Output
Click Run to see the output here.

Для словаря, в котором отсутствующие ключи должны авто-инициализироваться, стоит взглянуть на collections.defaultdict.

IndexError

main.py
Output
Click Run to see the output here.

«List index out of range». Ты попросил позицию, которой нет в последовательности.

Ремонт: проверка длины, -1 для последнего элемента или срез (numbers[5:6] вернёт [] вместо ошибки).

AttributeError

main.py
Output
Click Run to see the output here.

«'NoneType' object has no attribute 'upper'». Ты вызвал метод у объекта, у которого его нет. Почти всегда значит, что переменная — не того типа, часто None там, где ждал реальное значение.

Ремонт: выясни, откуда пришёл None. print(type(var)) или брейкпойнт прямо перед ошибкой — самый быстрый путь. Функции, которые «иногда падают», обычно возвращают None; проверяй возврат до вызова методов на нём.

ModuleNotFoundErrorImportError)

import fastapi

«No module named 'fastapi'». Пакет не установлен в тот Python, которым запускается скрипт. Две частых причины:

  1. Ты реально его не поставил. Запусти python -m pip install fastapi в правильном окружении.
  2. Поставил, но в другой Python. На macOS это случается постоянно, когда pip и python смотрят на разные установки.

Надёжный ремонт — ставить тем же интерпретатором, которым запускаешь:

python -m pip install fastapi

Если используешь виртуальное окружение (а стоит), убедись, что оно активировано и перед pip install, и перед python script.py.

FileNotFoundError

with open("settings.yaml") as f:
    config = f.read()

«[Errno 2] No such file or directory: 'settings.yaml'». Путь не существует относительно того места, где запускается скрипт.

Ремонт: распечатай os.getcwd() в начале скрипта, чтобы увидеть, где Python ищет. Используй абсолютные пути или pathlib.Path(__file__).parent / "settings.yaml", чтобы привязать путь к расположению скрипта.

EOFError

name = input("Name: ")

«EOF when reading a line». input() пытался прочесть из stdin и не получил ничего — либо пайп пустой, либо ты нажал Ctrl-D в приглашении.

Ремонт: если пайп легитимен — оберни вызов:

try:
    name = input("Name: ")
except EOFError:
    name = "anonymous"

В браузерном редакторе в этих документах рантайм симулирует ввод; здесь ты на это не наткнёшься.

IndentationError и SyntaxError

IndentationError: expected an indented block after function definition on line 2

Эти особенные — они срабатывают до запуска программы. Python отказался парсить файл.

  • IndentationError — тело def, if, for и т. д. отсутствует или сбито. Большинство редакторов визуализируют отступы; включи «show whitespace», чтобы замечать смешанные табы и пробелы.
  • SyntaxError — забыл двоеточие, не совпали скобки или опечатался в ключевом слове. Свежие версии Python указывают стрелкой (^) на виноватый символ.

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

RuntimeError

Универсальный «что-то пошло не так во время выполнения, и это не одно из более специфичных». RecursionError (превышение глубины рекурсии) — частая специализация. Библиотечный код часто кидает RuntimeError, когда находится в плохом состоянии.

Ремонт: читай сообщение, оно обычно описательное. Если дело в рекурсии — либо перепиши итеративно, либо в редких случаях подкрути sys.setrecursionlimit.

Отладка через print

Прежде чем тянуться к настоящему отладчику, print() — а лучше форма f"{var=}" — ловит большинство багов:

main.py
Output
Click Run to see the output here.

f"{var=}" печатает и имя выражения, и его значение — не надо переписывать имя в формате. Запускаешь скрипт, сканируешь вывод, находишь строку, где значение стало не тем. Большинство «таинственных» багов становятся очевидными после трёх-четырёх удачно поставленных print-ов.

Прежде чем коммитить, убери print-ы. logging.debug(...) приятнее, чем print, для кода, идущего в продакшн — отладочное логирование можно включать и выключать без правки строк.

breakpoint() и pdb

Когда print не хватает, breakpoint() опускает в интерактивный отладчик Python в этой точке:

def discount(price, percent):
    breakpoint()
    return price * (1 - percent / 100)

discount(100, 20)

Запусти скрипт в настоящем терминале. Окажешься в приглашении (Pdb). Команды, которые стоит знать:

  • p variable — распечатать переменную.
  • n — шагнуть на следующую строку.
  • s — войти в вызов функции.
  • c — продолжить до следующего брейкпойнта или конца.
  • q — выйти.
  • l — вывести исходник вокруг текущей строки.

Отладчики IDE (VS Code, PyCharm) оборачивают тот же протокол в GUI — брейкпойнты в полях, сайдбар с переменными. Выбирай то, что меньше трения.

Привычки, уменьшающие количество ошибок

  • Используй описательные имена переменных. Половина шума TypeError и AttributeError исчезает, когда ты не можешь забыть, что лежит в переменной.
  • Валидируй входы на границе. Распарсь и проверь пользовательский ввод или содержимое файла один раз в начале функции. Остальной код может доверять значениям.
  • Падай громко, не тихо. Голый except Exception: pass прячет ошибки, которые тебе на самом деле нужно видеть. Лови конкретные исключения, осознанно их обрабатывай, а остальное — пусть всплывает.
  • Сначала читай низ трейсбэка. Каждая минута, потраченная на обучение чтению трейсбэков, окупается стократ.

Большинство ошибок — не загадки, а однострочные опечатки или неверные типы с ясным сообщением. Доверяй сообщению об ошибке: оно обычно право.

У тебя получилось

Это конец справочной части. Ты прошёл от «что такое Python?» через переменные, управление потоком, коллекции, функции, классы, итерацию, реальные данные и ошибки. Дальше шаг — проектный: выбери то, что хочется построить, и двигайся к тем частям, которые нужно выучить глубже. Эти страницы никуда не денутся, когда вернёшься с конкретным вопросом.

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

Что такое KeyError в Python?

KeyError поднимается при попытке получить в словаре ключ, которого нет. users["missing"] даст KeyError: 'missing'. Безопасные альтернативы: users.get("missing", default), users.get("missing") (вернёт None) или явная проверка if key in users:.

Что такое EOFError в Python?

EOFError (end-of-file) поднимается, когда input() не может ничего прочитать из-за закрытого потока ввода. Чаще всего видишь, когда скрипту с input() ничего не подают через пайп, или когда нажал Ctrl-D в интерактивной сессии. Оберни в try/except EOFError, если скрипт должен уметь работать с пайпом.

Что такое ModuleNotFoundError?

ModuleNotFoundError означает, что import X не нашёл модуль X. Либо пакет не установлен (pip install X), либо установлен в другой Python, а не в тот, что запускает код (частая история, когда стоит несколько Python-ов). python -m pip install X чинит второй случай, используя тот же интерпретатор.

Как читать трейсбэк Python?

Читай снизу вверх. Последняя строка — тип исключения и сообщение: конкретно то, что пошло не так. Строки выше — стек вызовов, приведших сюда, твой код обычно ближе к низу. Перейди к файлу+строке в самом нижнем твоём фрейме — туда и идёт ремонт.

Учитесь программировать с Coddy

НАЧАТЬ