2025, Sep 27 01:16
E225 и E226 в Flake8: как pycodestyle проверяет пробелы вокруг операторов
Почему Flake8 отмечает пробелы вокруг операторов выборочно: роль pycodestyle, различия правил E225 и E226, примеры и настройка для предсказуемых проверок.
Почему Flake8 отмечает только часть пропусков пробелов вокруг арифметических операторов, а другие пропускает? Если вы видели, что E226 срабатывает на одной строке, а на другой — столь же сомнительной — нет, вы столкнулись с тонким разделением обязанностей в том, как под капотом делегируются проверки стиля.
Минимальный пример расхождения
Ниже — три на вид одинаковых выражения, но при игнорировании E225 Flake8 помечает E226 лишь первое:
x = 0*0  # помечается как E226
x = 0* 0  # не помечается как E226 при игнорировании E225
x = 0 *0  # не помечается как E226 при игнорировании E225
Если опираться на часто цитируемые рекомендации, логика кажется простой:
Перед и после арифметического оператора (+, -, / и *) должен быть один пробел.
Что на самом деле происходит
Такое поведение задаёт pycodestyle, а не сам Flake8. Flake8 выступает оболочкой и делегирует проверки стиля pycodestyle. Внутри pycodestyle.py правило E226 «отсутствует пробел вокруг арифметического оператора» реализовано через ветвления, которые отслеживают внутреннее состояние (например, с помощью переменных вроде need_space). От этого разветвления зависит, будет ли поднято E226 или E225 в тех или иных вариантах расстановки пробелов.
Коротко: E226 срабатывает, когда вокруг арифметического оператора нет пробелов ни слева, ни справа — это первый пример. Две другие строки попадают под E225, которое касается отсутствия пробела вокруг оператора в остальных случаях. Если вы игнорируете E225, будет отмечена только первая строка как E226, остальные пропустятся.
Ссылки: реализация в pycodestyle (pycodestyle Github) и описания правил E225/E226 (E225 Rule, E226 Rule).
Как добиться предсказуемости поведения линтера
Если нужно, чтобы отмечались все три строки, не игнорируйте E225. При включённом E225 он ловит случаи с частично расставленными пробелами, а E226 по‑прежнему охватывает полностью «сцепленные» операторы. На практике это означает: включите и E225, и E226, чтобы видеть все нарушения пробельной разметки.
Исправленный код
Чтобы соответствовать рекомендациям, ставьте по одному пробелу по обе стороны оператора:
y = 0 * 0
Есть ещё нюанс: срабатывание E226 зависит от контекста. pep8 предлагает использовать пробелы, чтобы подчёркивать приоритет операторов; например, предпочтительнее запись y = m*x + c, а не y = m * x + c. Отсюда и раздельные проверки E226 и E225, а также небольшие различия в их поведении.
Почему это важно для ваших инструментов
Понимание того, что Flake8 делегирует проверки pycodestyle, объясняет, почему одних только настроек Flake8 порой недостаточно и результаты кажутся «неконсистентными». Зная разграничение ролей между E225 и E226, проще настроить список игнорируемых правил и пороги в CI без сюрпризов — и не застревать на ревью из‑за мнимых «глюков» линтера.
Выводы
Если срабатывает только на полностью «безпробельный» оператор, значит, это зона ответственности E226; случаи с частичными пробелами относятся к E225. Включайте оба правила — E225 и E226 — чтобы охватить все проверки пробелов, оформляйте арифметические операторы пробелом с обеих сторон там, где это уместно, и помните: E226 допускает контекстные отступления для выражения приоритета.
Статья основана на вопросе со StackOverflow от ginjaemocoes и ответе от David Silveiro.