PEP 8: каким должен быть код на Python

Python имеет определенные стандарты кода, которым стараются следовать все программисты. Эти стандарты описаны в документации PEP8.

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

Почему важно стандартизировать код?

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

Если каждый программист будет писать код с разным стилем, то его анализ станет очень трудной задачей. Поэтому важно, чтобы Python-разработчики следовали определенным соглашениям, которые позволяют стандартизировать код, сделать его более понятным любому специалисту.

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

Внутри команды разработчиков может выработаться особый стиль написания кода, который может в некоторых местах нарушать принятые соглашения. Это нередкая и допустимая ситуация, однако программист должен помнить, что если он уйдет из этой команды, ему придется заново переучиваться писать код в соответствии с принятыми стандартами.

Разметка кода на Python

Этот раздел содержит указания, определяющие, как оформлять код на Python 3 (пробелы, отступы, строки).

Отступы

Для обозначения нового уровня вложенности используется четыре пробела.

При разделении аргументов функции на несколько строк размер отступа может быть разным.

Если это объявление или вызов функций (нет тела функции), то можно либо выравнивать следующие строки по открывающейся скобке:

f1 = func(first_arg, second_arg,
          third_arg, fourth_arg)

либо использовать четыре пробела, но с обязательным переносом первой строки:

f1 = func(
    first_arg, second_arg,
    third_arg, fourth_arg)
Использовать для продолжения именно 4 пробела – это не обязательное правило для строк продолжения перечисления. Можно использовать и другое количество пробелов, например, 2.

Если после списка аргументов следует еще какой-либо код (например, если это объявляется функция), то к отступу аргументов добавляется еще 4 пробела:

def func(
        first_arg, second_arg, 
        third_arg, fourth_arg):
    print(fourth_arg)

Это делается для того, чтобы отделить аргументы от тела функции.

В случае с оператором if, программист может как использовать, так и не использовать экстра отступы:

if(temp > 5 and
        temp < 25):
    some_func(some_args[])
if(temp > 5
    and temp < 25):
    some_func(some_args[])

Если не использовать дополнительные пробелы, то, при желании, можно отделить тело условного оператора однострочным комментарием. Это может улучшить читаемость в некоторых редакторах кода из-за подсветки комментария.

Закрывающая конструкция в функции или структуре может располагаться под первым символом нижней строки:

names = [
    "John", "Alex",
    "Olivia", "Jacob",
    ]

Также её можно поместить в самое начало строки:

f = some_f(
    "str1", "str2",
    "str3", "str4",
)

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

Максимальная длина строки

Программист не должен использовать более 79 символов в одной строке. Строки длинного многострочного текста (комментарии, документация) ограничены 72-я символами.

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

Круглые скобки — лучший способ реализовать разделение кода на несколько строк. Однако программисты также могут использовать знак обратной косой черты “\“.

Бинарные операторы и пробелы

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

Правильно:

math_rez = a * b – x + y

Неправильно:

math_rez=a*b–x+y

Кроме того, если операторы используются в многострочном выражении, то они всегда должны переноситься вместе с правым операндом:

max_sum = (first_sum
           + second_sum
           + third_sum)

Пустые строки

Определения внешних классов и функций окружается двумя пустыми строками (две строки сверху).

Методы внутри класса отделяются одной пустой строкой.

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

Нельзя использовать пустые строки между внешним и вложенным блоком кода.

Кодировка

Файлы с исходным кодом на Python 3 всегда должны иметь кодировку UTF-8. Раньше в Python 2 использовалась ASCII.

Если нужно использовать символы других кодировок, следует пользоваться экранирующими последовательностями: \x, \u, \U, \N.

Импорт

Импорт каждого нового модуля должен происходить в новой строке:

import sys
import time

При импорте нескольких частей модуля можно писать их в одной строке через запятую:

from time import sleep, ctime

Подключение модулей всегда находятся в начале файла, ниже строк документации и выше объявления констант.

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

  1. Стандартные библиотеки.
  2. Сторонние библиотеки.
  3. Другие модули проекта.

Использовать “*” при импорте считается плохим тоном. Дело в том, что такой импорт не дает представления об именах, которые находятся в импортированном пространстве имен, что не только сбивает с толку, но и может привести к ошибкам.

Кавычки в строках

В Python можно использовать как одинарные, так и двойные кавычки. Однако, если в строке используются двойные кавычки, то программист должен выделять строку одинарными и наоборот. Это позволяет повысить читаемость строки.

Для строк документации обязательно используется три двойных кавычки. Более подробнее это описано в стандарте PEP 257.

Пробелы в выражениях и операторах

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

  • Внутри фигурных, круглых или квадратных скобок.
    • Правильно:
      mix_arr = ("John", [176, 70], {"age" : 14})
    • Неправильно:
      mix_arr = ( "John", [ 176, 70 ], { "age" : 14 } )
  • Между запятой и закрывающей скобкой.
  • Перед запятой, точкой или двоеточием. Однако в операции среза двоеточие должно иметь одинаковое количество пробелов с обеих сторон.
    • Правильно: mix_arr[0:2] или mix_arr[0 : 2]
    • Неправильно: mix_arr[0 :2] или mix_arr[0: 2]
  • Между именем функции и скобкой с передаваемыми в неё аргументами.
    • Правильно:
      custom_function(args)
    • Неправильно:
      custom_function (args)
  • Нельзя использовать более одного пробела, чтобы выравнивать операторы присваивания разных выражений.
    • Правильно:
      weight = 70
      height = 1,76
      body_mass_index = 22,5
    • Неправильно:
      weight          = 70
      height          = 1,76
      body_mass_index = 22,5
  • Все операторы присваивания и сравнения должны отделяться от операндов пробелами.
  • Если в выражении используются операторы с разным приоритетом, и нужно подчеркнуть это, допускается использовать пробелы только вокруг этих операторов.
    • Пример:
      y = 2*x – 1/x
  • Если знак присваивания используется для задания параметра по умолчанию или именного аргумента, то он не отделяется пробелами.
    • Пример:
      def graph(x=0.0, y=0.0)
  • Не пишите несколько инструкций в одной строке (разделенных точкой с запятой).
    • Неправильно:
      x = y + 1; y = y + 1; x = y * 1.1
  • Если тело цикла состоит из одной короткой строки, то его можно писать в той же строке, что и цикл.
    • Пример:
      while isAlive: increase_hunger()

Использование запятых

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

  • Правильно:
    names = ("John",)
  • Допускается, но не рекомендуется:
    names = "John",

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

  • Правильно:
    names = [
        "John",
        "Olivia",
        ]
  • Неправильно:
    names = ["John", "Olivia",]

Комментарии

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

Комментарии должны отражать суть кода, а не противоречить ему. Если код по какой-то причине изменяется, комментарии также необходимо изменить.

Все комментарии должны быть законченными предложениями, и если первое слово не является идентификатором, то оно должно начинаться с заглавной буквы.

Все комментарии должны быть написаны на английском языке, даже если программисты не из англоговорящей страны и на данный момент над проектом работают не англоговорящие программисты.

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

Блочные комментарии

Блочные комментарии используются, когда необходимо объяснить действий какого-либо блока кода. Как правило, такие комментарии размещаются над блоком кода на отдельной строке.

# Этот код делает что-то очень интересное
a = 5
b = 10
a = b - a + a

Комментарии “в строке”

Это комментарии, которые объясняют действия строки кода и пишутся в той же строке, что и код. Они должны отделяться от кода не менее чем двумя пробелами.

Такие комментарии не рекомендуется использовать, потому что в большинстве случаев они объясняют очевидные вещи и не несут никакой практической пользы.

a = a / 2 # Деление числа на два

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

a = a / 2 # Получение середины экрана

Строки документации

Все открытые модули, функции, классы и их составляющие должны документироваться. Это правило не относится к приватным методам, однако между строкой с “def” и телом метода можно написать комментарий, который описывает назначение метода.

Более подробно про соглашение о документации рассказано в PEP 257. Кавычки, показывающие окончания строк документации, должны переносится на новую строку.

"""Speed determination.

Keyword arguments:
distance -- distance traveled in meters
time -- time in seconds (default 1)
"""

Однако, если документация состоит из одной строки, то кавычки не переносятся.

"""Some info about something."""

Правила по выбору имён

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

Если по какой-то причине в библиотеке используется собственный стиль имён, нарушающий принятый стандарт, то программист должен писать код в том стиле, который использует библиотека, чтобы не нарушать внутреннюю согласованность кода.

Главный принцип

Если имя является открытой частью интерфейса прикладного программирования, то оно должно отражать не реализацию, а использование.

Стили имен

Выбирать имена в Python можно в соответствии с одним из многих стилей. Определить, какой стиль наименования используется, можно независимо от того, для чего он используется.

Обычно используются следующие стили:

  • b (одиночная строчная буква)
  • B (одиночная заглавная буква)
  • lowercase (нижний регистр)
  • lower_case_with_underscores (нижний регистр с нижней чертой-разделителем)
  • UPPERCASE (верхний регистр)
  • UPPER_CASE_WITH_UNDERSCORES (верхний регистр с нижней чертой-разделителем)
  • CapitalizedWords (CamelCase) – каждое новое слово начинается с заглавной буквы
  • mixedCase (отличается от предыдущего тем, что первая буква в нижнем регистре)

Имена, которые лучше не использовать

Никогда не используйте строчные английские буквы: l (“эл”), O (заглавная “о”) и I (заглавная “ай”). Заглавная “о” неотличима от нуля, а “l” и “I” друг от друга.

Если всё же возникла необходимость использовать l (“эл”), замените её на заглавную “L”.

Имена пакетов и моделей

Модули должны иметь короткие имена в нижнем регистре. В именах модулей допускается использовать нижние подчеркивания, если это улучшает читаемость.

Если модуль на C или C++ сопровождается модулем Python, обеспечивающим более высокоуровневый интерфейс, то имя C/C++ модуля начинается с символа нижнего подчеркивания (_modulename).

Имена классов

Классам дают имена в соответствии со стилем наименования CapitalizedWords.

Имена исключений

Из-за того что исключения по сути являются классами, к ним применяется то же соглашение об наименованиях, что и для классов.

Программист может добавить суффикс “Error”, чтобы подчеркнуть, что исключение является ошибкой.

Имена глобальных переменных

Глобальные переменные именуются по тем же соглашениям, что и функции. Кроме того, глобальные переменные стоит использовать только в пределах одного модуля.

Если модуль предполагается импортировать командой from module import *, следует описать все разрешенные к импорту объекты в __all__. Это предотвращает импорт глобальных переменных, а также импорт тех объектов, которые в соответствии со своей реализацией не должны быть доступны извне.

__all__ – это список доступных для импорта объектов, то есть публичных.

Имена функций и переменных

Для имен функций используется нижний регистр. Если необходимо повысить читаемость, можно разделять слова символом нижнего подчеркивания.

Имена переменных выбираются по тем же правилам, что и имена функций.

В случаях, если требуется сохранить обратную совместимость с библиотекой (например, threading.py), допускается использовать mixedCase.

Имена аргументов функций и методов

Для методов экземпляра в качестве первого аргумента всегда используется self, а для методов класса — cls.

Если аргумент функции имеет имя, которое конфликтует с зарезервированным ключевым словом языка, следует добавить в его конец символ нижнего подчеркивания. Это лучше, чем сокращать или менять имя с потерей смысла.

  • Правильно:
    tuple_
  • Неправильно:
    tpl
    tupl

Имена переменных и методов экземпляров класса

Тот же стиль, что и для функций: нижний регистр и нижние подчеркивания при необходимости.

Для закрытых методом и атрибутов экземпляра используйте нижнее подчеркивание в начале имени (_method).

Чтобы не допустить конфликта имён с подклассами, следует использовать два символа нижнего подчеркивания в начале имён. Если класс Animal имеет атрибут __a, обращение вида Animal.__a не будет работать (в этом случае можно использовать Animal._Animal__a), так как интерпретатор изменит имя. Двойное подчеркивание следует использовать только для того, чтобы избежать конфликта имён в классах и подклассах.

Константы

Константы определяются на уровне подключения модулей и пишутся в верхнем регистре с разделением слова символами подчеркивания.

Примеры:

  • TOTAL_SUM
  • SUM
  • TOTAL

Рекомендации по программированию

  • Код должен быть совместимым с другими реализациями Python, такими как PyPy, IronPython и другие.
  • Если необходимо сравнить что-либо с такими объектами языка, как None, обязательно используйте операторы is или is not, а не знак равно.
    Кроме того, никогда не делайте проверку if x is not None (если x не является None). Так как это может привести к ошибке, если x – контейнер.
  • Выражения “is not” и “not … is” ничем не отличаются друг от друга по функционалу. Однако для лучшей читаемости кода лучше использовать первое выражение.
  • Не присваивайте переменной лямбда-выражение, потому что преимущество лямбда-выражения в том, что оно может быть встроено в длинный код. Вместо этого объявите функцию с помощью def.
  • Если нужно перехватить исключение, указывайте конкретную ошибку. Если просто написать except, то компилятор будет перехватывать все исключения, что обязательно приведет к проблемам.
    • Правильно:
      try:
          import some_module
      except ImportError:
          print("Импорт невозможен")
    • Неправильно:
      try:
          import some_module
      except:
          print("Я не задал тип ошибки, "
                "вы не сможете использовать ctrl+c")
  • Внутри конструкции для отлавливания исключений должно быть минимум кода. Если это правило не соблюдено, то может быть не очевидно, что стало причиной ошибки.
  • Чтобы сравнить тип двух объектов, используйте специальную функцию isinstance(), а не оператор is.
    • Правильно: isinstance(object, int)
    • Неправильно: type(object) is type(99)
  • Нельзя сравнивать переменную с логическим типом с помощью равенства или is.
    • Правильно:
      if isAlive:
    • Неправильно:
      if isAlive == True:
    • Неправильно:
      if isAlive is True: