Типизация всерьёз
как заставить аннотации проверять код ИИ
Что это
Статья 2.4 объясняла, как читать аннотации типов. Здесь — как превратить их из комментария в проверку.
Сами по себе аннотации Python ничего не проверяют: напишешь -> str, вернёшь
None — он промолчит. Но есть инструмент, который их читает и проверяет, и для
работы с ИИ это один из самых выгодных приёмов во всей книге.
Как выглядит в коде
Код, который выглядит правильно:
def find_city(name: str) -> str | None:
cities = {"oslo": "Осло", "bergen": "Берген"}
return cities.get(name.lower())
def greet(name: str) -> str:
city = find_city(name)
return f"Привет из города {city.upper()}"Запускается без ошибок — пока запрашивают существующий город. Проверка:
python3 -m mypy --strict mypydemo.pymypydemo.py:8: error: Item "None" of "str | None" has no attribute "upper" [union-attr]
Found 1 error in 1 file (checked 1 source file)Переводится так: find_city может вернуть None, а у None нет метода
upper. Ошибка найдена до запуска, без тестов, без воспроизведения,
без единого пользователя.
После починки:
def greet(name: str) -> str:
city = find_city(name)
if city is None:
return "Город не найден"
return f"Привет из города {city.upper()}"Success: no issues found in 1 source filegreet("oslo") -> Привет из города ОСЛО
greet("paris") -> Город не найденПочему это важно именно при работе с ИИ
Вернись к главе 4: там целая глава о том, как руками ловить ошибки, которых не видно при запуске. Проверка типов ловит целый класс таких ошибок механически:
| Ошибка ИИ | Ловится типами |
|---|---|
Забыл проверить None | да |
| Перепутал строку и число | да |
| Вызвал метод, которого нет | да |
| Передал не те аргументы | да |
| Выдумал метод библиотеки (статья 4.8) | да, если у библиотеки есть типы |
Это не заменяет чтения кода. Но из четырёх обязательных проверок (статья 4.1) одну теперь делает машина, каждый раз, бесплатно.
Как начать на существующем проекте
Проверять строго сразу — значит утонуть в сотнях ошибок. Разумный путь:
pip install mypy
python3 -m mypy weatherbot/ # без --strict, посмотреть масштабДальше — по одному модулю: добавить аннотации, добиться чистоты, перейти к
следующему. Настройки складывают в pyproject.toml:
[tool.mypy]
python_version = "3.12"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "weatherbot.storage.*"
strict = trueТак строгость включается там, где уже навели порядок.
Как сказать ИИ
Просить типы надо явно — по умолчанию их пишут не везде:
Добавь аннотации типов во все функции этого модуля.
Проверь, что mypy --strict проходит. Логику не меняй.Сильный приём — попросить проверить самого себя:
Прогони mypy --strict по своему коду мысленно: какие
ошибки он найдёт? Если найдёт — сразу исправь.И самый полезный — типы как способ сформулировать задачу:
Сигнатура должна быть такой:
def parse_report(raw: str) -> list[CityTemp]:
где CityTemp — dataclass с полями name: str и temp: float | None.
Реализацию пиши под эту сигнатуру.Так типы становятся частью постановки задачи (статья 3.4): они точнее слов и проверяются машиной.
На что смотреть
Аннотации есть, mypy не запускался. Самый частый случай: типы написаны
для красоты и давно разошлись с кодом.
Any повсюду. def handle(data: Any) -> Any — аннотация, которая ничего
не обещает. ИИ ставит Any, когда не уверен; это место стоит уточнить.
# type: ignore без объяснения. Способ заглушить проверку. Иногда
оправдан, но комментарий должен говорить почему.
-> None у функции, которая что-то возвращает. Аннотации не проверяются
при запуске, и такое расхождение живёт годами.
Типы только в сигнатурах, без --strict. Без строгого режима mypy
пропускает нетипизированные функции целиком — проверка оказывается
видимостью.
Шпаргалка
Аннотации сами по себе ничего не проверяют, нужен
mypy.python3 -m mypy --strict файл.py— одна команда, ловит целый класс ошибок ИИ.Самое ценное: забытая проверка на
Noneнаходится до запуска.На готовом проекте включай строгость по модулям, а не сразу везде.
Anyи# type: ignore— места, где проверка отключена.Сигнатура в запросе — самый точный способ поставить задачу.