Читать книгу «MINI DOOM Современный Python через игру Том 1 Учимся держать оружие» онлайн полностью📖 — Алексей Примак — MyBook.

Когда Python ругается

Рано или поздно — скорее рано — ты запустишь программу, а вместо результата получишь простыню красного текста. Это нормально. Опытные программисты видят такое по сто раз на дню и не расстраиваются. Ошибки бывают трёх видов, и полезно понимать, кто именно ругается и когда.

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



Листинг 1.5 — Забыли закрывающую скобку в строке 2


Сообщение выглядит пугающе, но устроено всегда одинаково. Разберём его по частям на рисунке 1.3.




Рисунок 1.3 — Анатомия сообщения об ошибке: файл, строка, тип и суть


Python говорит: в файле main.py, в строке 2, открытая скобка так и не закрылась, и галочкой ^ показывает, какая именно. Обрати внимание: строка 1 тоже не выполнилась, MINI DOOM не напечатался. Синтаксическая ошибка останавливает всё ещё до старта.




Второй вид — ошибка во время выполнения. Код написан грамматически правильно, но делает невозможное. Такие ошибки проявляются, только когда выполнение до них дойдёт. В листинге 1.6 вместо print написано pirnt.




Листинг 1.6 — Опечатка в имени функции


Видишь? Первые две строки отработали и напечатали своё, а на третьей программа упала. Это трейсбек (traceback) — отчёт о том, где и почему всё сломалось. Читать его надо снизу: последняя строка — суть. NameError: имени pirnt не существует. Python даже догадывается, что ты имел в виду print. Строкой выше — сама виноватая строка, а над ней — файл и номер строки. Четвёртая строка, Ready., так и не выполнилась.

Вот почему такие ошибки опасны. Представь, что опечатка не в третьей строке, а в коде, который срабатывает, только когда игрок подберёт секретную ракетницу на пятом уровне. Ты можешь сто раз запустить игру, и всё будет работать. А потом игрок дойдёт до ракетницы, и игра вылетит у него. Лучше бы поймать ошибку заранее. Для этого и нужен линтер — программа, которая читает код, не выполняя его, и ищет подозрительное. Мы поставили Ruff. Проверим им тот же файл в листинге 1.7.




Листинг 1.7 — Тот же файл глазами Ruff: ошибка найдена без запуска


Ruff нашёл ошибку, не запуская программу: F821 — неопределённое имя pirnt, строка 3, столбец 1. Буква с цифрами в начале — код правила, по нему удобно искать объяснения в документации Ruff.

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




Листинг 1.8 — Строку нельзя сложить с числом


Снова трейсбек, и снова строка 2 успела выполниться. TypeError: склеивать можно только строку со строкой, а не с int, то есть целым числом. Волнистая линия под кодом показывает, какая операция не удалась, а галочка — где именно плюс.

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




Листинг 1.9 — Ошибку типов находит mypy


mypy пишет: строка 3, неподдерживаемые типы для + — str и int, то есть строка и целое число. Как правильно печатать числа вместе с текстом, разберём в следующей главе. Самый простой способ ты уже знаешь: print(«AMMO:», ammo) — через запятую, и print сам превратит число в текст.

Сводка — в таблице 1.2.




Таблица 1.2 — Первые ошибки, которые ты встретишь, и кто их ловит


Главные правила чтения ошибок такие:

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

— Смотри на номер строки и на строку выше.

— Читай суть целиком, а не только слово Error. Python обычно говорит прямо, чего ему не хватает, и часто подсказывает: Did you mean…?

— Если ничего не понятно — скопируй последнюю строку и поищи её в интернете. С этой ошибкой до тебя уже встретились тысячи людей.

Настраиваем строгость

Ruff и mypy по умолчанию добрые: проверяют немного и закрывают глаза на многое. Мы сделаем из них злых прапорщиков. Настройки проекта в Python живут в файле pyproject.toml в корне папки. Создай его рядом с main.py и заполни, как в листинге 1.10.




Листинг 1.10 — Настройки проекта: строгий Ruff и строгий mypy


Раздел [project] описывает сам проект: имя, версию и минимальную версию Python. Раздел [tool.ruff.lint] включает наборы правил Ruff: каждый код — отдельная группа проверок, от стиля (E, W) и явных ошибок (F) до подозрительных конструкций (B), устаревших приёмов (UP) и лишних сложностей (SIM, PL). Названия групп можно не запоминать: Ruff в каждом замечании пишет код правила, а по коду легко найти объяснение. Строка ignore выключает три правила, которые ругаются на русские буквы в комментариях, и одно, которое в учебных примерах только мешает. Раздел [tool.ruff.lint.pylint] чуть смягчает одно правило: Ruff по умолчанию считает подозрительной функцию больше чем с пятью параметрами, а в игре рисование прямоугольника — это четыре координаты, цвет и сам холст. А strict = true в разделе [tool.mypy] включает у mypy самый строгий режим.

Каждый пример в этой книге проходит обе проверки без единого замечания, прежде чем попасть в листинг. Как это выглядит в терминале, показано в листинге 1.11: так стоит проверять свою программу перед каждым запуском.




Листинг 1.11 — Проверка перед запуском: Ruff, mypy и только потом программа