Команда Python for Devs подготовила перевод статьи о PEP 8. Мысль проста: споры о стиле в Python часто сводятся к одному — snake_case против camelCase. Даже сам Python не следует своим же правилам. Так стоит ли вообще относиться к PEP 8 как к догме?


Закон Свейгарта о жалобах на PEP 8 звучит так: «Всякий раз, когда кто-то жалуется на то, что код нарушает PEP 8, речь всегда идёт о том, что в коде используется camelCase вместо snake_case. Никогда жалоба не касается другой части PEP 8». Но в чём вообще смысл документа Python Enhancement Proposal №8, и как его используют (и злоупотребляют им)? Почему мы пишем код именно так, и насколько осмысленны разговоры о стиле и читаемости кода?

Что такое PEP 8 и зачем он нужен

PEP 8 описывает соглашения о стиле кода на Python. Будучи написанным создателем языка и ядром разработчиков с десятилетиями опыта, он имеет огромный авторитет. Последовательный стиль — это ключ к читаемости кода. Читаемость кода — одновременно объективная метрика и субъективное мнение, признак зрелой инженерной практики и в то же время абсолютная мелочь. Поэтому, конечно, именно об этом программисты любят спорить в интернете.

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

Необходимость языков, повышающих надёжность и упрощающих поддержку, хорошо известна. Поэтому акцент был сделан на читаемости программ, а не на простоте их написания.

При этом читаемость вовсе не обязательна для корректной работы программы. Компьютеру всё равно, какие вы выбрали имена переменных или пробелы. А у разработчиков под дедлайнами всегда есть соблазн сначала «просто написать код», а уже потом привести его в порядок. В моей книге Making Games with Python & Pygame есть версия игры Memory Puzzle, где все имена переменных и функций заменены на случайные буквы. И программа прекрасно работает (и даже LLM вроде ChatGPT понимают её без проблем). Но покажите этот код человеку — и он будет в замешательстве:

def f(bbb, pp):
    for bb in range(10):
        for ee in range(7):
            oo, ddd = aa(bb, ee)
            if not pp[bb][ee]:
                pygame.draw.rect(b, (255, 255, 255), (oo, ddd, 40, 40))
            else:
                ss, tt = s(bbb, bb, ee)
                w(ss, tt, bb, ee)

Конечно, такие крайности — редкость. Но даже мелкие огрехи читаемости могут стать препятствием к пониманию. Именно поэтому в PEP 20, «Дзен Питона», есть правило: «Readability counts» — «Читаемость имеет значение». (Там же есть и «Должен быть один — и желательно только один — очевидный способ сделать это», что было уколом в сторону перловского лозунга «Есть больше одного способа это сделать!». Проблема в том, что если в Perl есть пять способов, то программисту Perl придётся выучить все пять, чтобы понимать чужие программы.)

PEP 8 даёт множество указаний, как писать «читаемый» код. Но самое важное — первая часть документа после введения, "A Foolish Consistency is the Hobgoblin of Little Minds":

Одна из ключевых идей Гвидо: код читают гораздо чаще, чем пишут. Рекомендации, приведённые здесь, должны улучшить читаемость и обеспечить единообразие во множестве Python-проектов. Как сказано в PEP 20: “Readability counts”.

Стиль нужен ради согласованности. Важно быть последовательным в рамках этого гайда. Ещё важнее — быть последовательным в рамках проекта. А важнее всего — последовательность в одном модуле или функции.

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

Особенно: не ломайте обратную совместимость только ради соответствия этому PEP!

Иными словами, сам PEP 8 довольно прагматичен: его цель — помочь с согласованностью, даже если стиль проекта отличается от «канонических» правил. Но никогда не недооценивайте способность программистов превращать мелочи в поводы для войны.

Bike Shedding

Термин «bike shedding» («велосипедный сарай») или закон тривиальности Паркинсона описывает ситуацию, когда непропорционально много внимания уделяется мелким, но понятным деталям. Обсуждая проект атомной электростанции, люди будут дольше спорить о том, какого цвета покрасить сарай для велосипедов.

В Open source есть тяга внести хоть какой-то вклад, чтобы можно было гордо назвать себя «контрибьютором». Но порог входа обычно высок: чтобы реально помочь проекту, нужны усилия. Проще всего открыть pull request с правкой какой-нибудь мелочи.

С другой стороны, опытные (но не всегда зрелые) разработчики могут считать, что их стиль кода — единственно правильный, и пытаться навязать его проекту.

Любое изменение кода несёт риск багов. Правило «не трогай, если работает» может тормозить улучшения, но защищает от бессмысленных изменений ради самих изменений. И в обоих случаях проще всего прикрыться аргументом: «Так написано в PEP 8».

Закон Свейгарта о жалобах на PEP 8

В PEP 8 полно конкретных указаний: ограничивать длину комментариев 72 символами, ставить оператор в начале строки в многострочных выражениях, использовать запятую после последнего элемента в многострочном списке (но не в однострочном).

Но никто не жалуется на эти нарушения. Есть лишь одно правило, которое цитируют всегда. Поэтому я и сформулировал закон:

Всякий раз, когда кто-то жалуется на нарушение PEP 8, речь всегда идёт о том, что код написан в camelCase вместо snake_case. Никогда — ни о чём другом.

В переменных из нескольких слов есть два популярных стиля: snake_case — слова разделяются подчёркиванием и camelCase — слова разделяются заглавной буквой, делаяИмяПохожимНаГорбыВерблюда.

Лично я люблю camelCase: не нужно печатать лишние символы, и читается он, на мой взгляд, ничуть не хуже. PEP 8 советует snake_case. Формально я «нарушаю PEP 8», но сам PEP 8 же говорит: если стиль проекта единообразен — это важнее.

В первых двух изданиях моей книги Automate the Boring Stuff with Python я использовал camelCase. Угадайте, какая была самая частая жалоба?

Нет, не на то, что комментарии длиннее 72 символов.

Теоретически, кто-то мог бы сослаться на какую-то другую часть PEP 8. Но я с таким никогда не сталкивался. В моей книге были и, возможно, до сих пор есть ошибки. Но на это закрывают глаза, ведь гораздо проще сказать: «его книга не соответствует PEP 8».

В третьем издании я проделал огромную работу — переписал весь код (600 страниц) на snake_case. Код работал точно так же, читаемость спорна, но жалобы исчезли.

Забавно, но все прочие нарушения PEP 8 остались. Просто на них никто не обратил внимания.

Зачем нужны правила стиля

Главная цель гайдов по стилю — останавливать бессмысленные споры. Скобка на этой строке или на следующей? Ответ зрелого разработчика: «Неважно. Давайте выберем что-то одно и поедем дальше». Всё равно что ездить слева или справа: главное — одинаково.

Такие правила можно закрепить автоматическими форматтерами (Black, Ruff и т. п.), и это экономит нервы и деньги, ведь время разработчиков дорого.

Но для тех, кто хочет спорить до упора, это лишь смещает тему: не «что говорит гайд», а «каким он должен быть». Это споры без конца. Один громкий голос победит — другой потребует всё вернуть обратно.

Мой совет:

  • Игнорируйте. Не отвечайте на письма, не мерджите PR.

  • Согласитесь, но попросите добавить тесты на другие нарушения PEP 8.

  • Попросите конфиг для Black или Ruff. Пусть сами разберутся.

  • Скажите: «Да, вы правы, но изменения сломают обратную совместимость».

  • Иногда — просто уступите, если это снимает шум.

Немного цинизма, немного прагматизма. Жизнь коротка, и объяснять каждую мелочь тем, кто не хочет слушать, — пустая трата сил.

Python сам нарушает PEP 8

И если вы всё ещё считаете, что догматичное следование PEP 8 обязательно, мой последний аргумент: сам Python его нарушает.

  • Константы должны быть в ALL_CAPS, но в модуле mathpietaunaninf.

  • Имена должны быть в snake_case, но у unittest есть setUp() и tearDown(). У строковых методов — isalpha() и startswith().

  • Константы должны разделять слова подчёркиванием, но в reIGNORECASEDOTALL.

  • Классы должны называться с заглавной буквы, но intfloatstrlistdict — нет.

  • Нельзя использовать префиксы в именах, но есть st_modest_sizest_mtime.

Примеры можно множить бесконечно. Python старый, и во многом это исторические рудименты. Но язык настолько популярен и устоялся, что «чинить» эти вещи бессмысленно: цена изменений огромна, пользы почти нет. Даже переход с Python 2 на 3 их не затронул.

Разработка ПО — это не только техника, но и социальный процесс. Когда проект выходит за рамки одного-двух человек, начинается политика. А если добавить сюда разработчиков, уверенных, что их вкусы — это математическая истина, то бесплодные споры гарантированы.

Хотелось бы иметь объективный инструмент, чтобы отсеивать такие «шумные» помехи, но увы. Думаю, на этот пост я уже потратил достаточно времени. Пора вернуться к работе…

Русскоязычное сообщество про Python

Друзья! Эту статью подготовила команда Python for Devs — канала, где каждый день выходят самые свежие и полезные материалы о Python и его экосистеме. Подписывайтесь, чтобы ничего не пропустить!

Комментарии (0)