В Python пять тайп-чекеров — и блог советует запускать все сразу

Семистрочная функция в библиотеке Polars требует четырёх разных комментариев type-ignore, чтобы угодить четырём разным чекерам. Вывод авторов Pyrefly: запускайте как можно больше чекеров на своих тестах.

Вкратце

mypy, Pyright, Pyrefly, ty и Zuban теперь все проверяют типы в Python — и каждый расходится с остальными в том, что считается валидным. Пост команды Pyrefly показывает один оверрайд __eq__ в Polars, требующий четырёх игнор-комментариев на семи строках, и предлагает выход: гонять каждый доступный чекер по тест-сьюту, а не по исходникам.

Тред разделился. Одни спрашивают, зачем вообще прикручивать строгую типизацию к динамическому Python; другие возражают: там, где ошибки стоят дорого, чекеры своё отрабатывают.

Пять чекеров, четыре игнор-комментария, семь строк кода

Логотип Pyrefly
Логотип Pyrefly

Заголовок поста команды Pyrefly — это настоящий вопрос, с которым сталкиваются авторы библиотек: если mypy, Pyright, Pyrefly, ty и Zuban проверяют типы Python и каждый реализует частично стандартизированный typing-spec чуть по-своему, неужели от вас ожидают запуска всех пяти? Показательный пример — один оверрайд __eq__ из библиотеки для датафреймов Polars. Чтобы пройти через каждый чекер, семи строкам нужно четыре разных комментария-заглушки:

@overload  # type: ignore[override]
def __eq__(  # pyrefly: ignore[bad-override]
    self, other: pl.DataTypeExpr
) -> pl.Expr: ...
@overload
def __eq__(self, other: PolarsDataType) -> bool: ...
def __eq__(...):  # ty: ignore[invalid-method-override]  # pyright: ignore[reportIncompatibleMethodOverride]

Реакция самих авторов: «Целых 4 разных комментария type-ignore для 7 строк кода!» Оператор == здесь возвращает не bool по той же причине, что и в numpy или SQLAlchemy: перегруженные операторы строят выражения запроса или поэлементные булевы массивы, а не одно булево значение.

Главный совет: проверяйте тесты, а не исходники

Тезис поста переворачивает привычный подход. Вместо того чтобы тратить силы на типизацию собственных исходников, авторы предлагают: «Приоритет — запускать как можно больше тайп-чекеров на тест-сьюте. Хотя бы один — на исходном коде.» Логика простая: пользователи библиотеки используют разные чекеры, и их интересует, порождает ли ваш публичный API ошибки в их окружении. Та самая функция Polars, которой понадобились четыре игнор-комментария в исходниках, чисто проходит все пять чекеров при вызове через тест — значит, именно тест даёт реальную ценность мульти-чекерного прогона.

Автор, активно участвовавший в дискуссии, объяснил, почему это специфически питоновская проблема:

«Запуск нескольких тайп-чекеров — это не про строгость… Экосистема типизации Python уникально фрагментирована: стандартизация между несколькими популярными инструментами лишь частичная.» — автор поста

Тред: «самый ленивый из всех — mypy» и другие полевые заметки

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

Голос Инструментарий / позиция
Параллельный запуск pyright в CI, mypy локально — ловят разные баги
Скептик mypy mypy «тормозит» и «самый ленивый из всех», пропускает много ошибок
Сторонник uv ty + ruff достаточно; смысла добавлять чекер нет
Пользователь PyCharm встроенный инференс превосходит отдельные инструменты за счёт глубокого анализа наследования

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

«Я запускаю pyright в CI и mypy локально. Они ловят разное — pyright строже с оверлоудами, mypy лучше находит проблемы с None в нашей кодовой базе. Раздражает, но я так и не нашёл одного, который покрывает оба случая.» — инженер, использующий два чекера в CI

«Почему кто-то до сих пор использует mypy, кроме как для легаси — за гранью моего понимания. Он жутко медленный и самый ленивый из всех, пропускает кучу ошибок.» — Django-разработчик, разочарованный в mypy

Один высококарматный комментатор выдал достойный оглавления итог новых консенсусных инструментов: «Всё, что не uv, ty, ruff — устарело и неправильно» — на что последовал вопрос: не обновит ли он этот список через месяц.

Глубинный разлом: нужна ли строгая типизация Python вообще

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

«Есть много людей, которые любят Python и хотят использовать его там, где ошибки имеют серьёзные последствия. Проверка типов помогает в таких контекстах… Отталкивать тех, кто хочет использовать все доступные инструменты для написания корректного Python, наносит вред сообществу.» — разработчик, защищающий опциональную строгость

«Python с типизацией лучше, чем без неё.» — комментатор о тех, у кого нет выбора языка

Самый резкий критик утверждал, что вся проблема раздута: исключения от неправильного типа не катастрофа, а нахождение ошибок через тайп-чекинг функционально ничем не отличается от их нахождения через тест-сьют. Один комментатор объяснил, почему «строгая» типизация редко даёт то, что обещает:

«[Для этого] каждому типу нужно определить конечный диапазон значений… Если такая система есть (что-то вроде Coq к ней близко), то если программа компилируется — она по определению корректна. Но даже самые убеждённые сторонники типизации не хотят этим заниматься, потому что понимают, сколько времени займёт написание кода.» — скептик Python в продакшене

А в одном пожелании описывалась система типизации, которую многие хотели бы видеть: вывод типов по умолчанию, основанный на ограничениях, — пишешь def foo(a, b): return a + b, чекер говорит, что foo(5, {}) не работает, потому что + для int и dict нет, — аннотации только когда нужно сузить выведенные ограничения, а не переформулировать очевидное.

Итог: фрагментация — это и есть продукт

Совет из поста — не «запускайте пять чекеров», а стратегия выживания для авторов библиотек, чьи пользователи разбрелись по пяти несовместимым инструментам. Для разработчиков приложений вывод уже, но полезнее: выберите один чекер для исходников, а если публикуете публичный API — прогоняйте его через тесты в том окружении, которое используют ваши пользователи. Повторяющаяся жалоба в треде — что всё это лишь линтинг, прикрученный к динамическому рантайму, и приходится платить за обоих — это то, что никакой набор инструментов не исправит.

Получайте такие разборы каждый день

Главные истории Hacker News — на email, в Telegram или RSS.

Следующая новость · 6 из 31 Читать дальше
🚀Tech

Rust-форж «лучший GitHub» вышел как антиИИ-продукт — модератор dang убрал это из заголовка

Gitdot представился быстрым опенсорсным GitHub без ИИ. Комментаторы открыли его исходный код и нашли дюжину файлов CLAUDE.md — а через несколько часов модератор тихо убрал «anti-AI» из заголовка Show HN.

★ 197 · 💬 154 · gitdot.io · 5 мин