CodingStyle/Python
Стандарт оформления исходного кода на Python
Данный стандарт выработан с учетом опыта разработки нескольких проектов и обязателен к использованию всеми программистами Etersoft, разрабатывающими на языке Python.
За основу взяты Google Coding Style, Qt Coding Style и некоторые другие.
- http://qt.gitorious.org/qt/pages/QtCodingStyle
- http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
Отступы
В качестве отступов в исходном коде следует использовать символы табуляции, но не пробелы. Ширина табуляции может настраиваться в текстовом редакторе так, как удобно для восприятия разработчику, в отличие от пробелов, количество которых нельзя уменьшить или увеличить в коде, не переписывая его весь регекспами.
В рамках одного файла с исходным кодом (в дальнейшем - модуля) ни в коем случае нельзя использовать разные виды отступа (пробелы и табуляции одновременно), так как интерпретатор воспримет их некорректно. Типы отступа могут различаться в каждом модуле, но делать это крайне не рекомендуется, поскольку такой подход приведет к путанице и проблемам в дальгейшем.
Некоторые сотрудники, (например, sin@) считают более правильным использование пробелов. Поскольку с его мнением трудно не считаться :-), то было принято следующее правило: тип отступов определяет первый коммитер проекта, его руководитель. Остальные следуют его примеру. Кроме этого пункта, остальные правила кодинг-стайла остаются неизменными.
Настройка величины табуляции для разных редакторов
- Vim: для настройки введите "ESC :set ts=6", таким образом символ табуляции визуально будет выглядеть, как 6 пробелов. Для сохранения настройки надо прописать опцию в конфиг: "echo "set ts=6" >> /.vimrc". Для быстрого преобразования кода, содержащего 2, 4, 6 или 8 пробелов к стандартным табам, можно воспользоваться таким мапом клавиш:
set wildmenu
set wcm=<Tab>
menu SpacesRefactoring.[2\ Spaces\ to\ Tab] :%s#^\( \{2}\)\+#\=repeat("\t", len(submatch(0))/2)#g<Cr> menu SpacesRefactoring.[4\ Spaces\ to\ Tab] :%s#^\( \{4}\)\+#\=repeat("\t", len(submatch(0))/4)#g<Cr> menu SpacesRefactoring.[6\ Spaces\ to\ Tab] :%s#^\( \{6}\)\+#\=repeat("\t", len(submatch(0))/6)#g<Cr> menu SpacesRefactoring.[8\ Spaces\ to\ Tab] :%s#^\( \{8}\)\+#\=repeat("\t", len(submatch(0))/8)#g<Cr>
menu SpacesRefactoring.[Tab\ to\ 2\ Spaces] :%s#^\(\t\+\)#\=repeat(" ", len(submatch(0))*2)#g<Cr> menu SpacesRefactoring.[Tab\ to\ 4\ Spaces] :%s#^\(\t\+\)#\=repeat(" ", len(submatch(0))*4)#g<Cr> menu SpacesRefactoring.[Tab\ to\ 6\ Spaces] :%s#^\(\t\+\)#\=repeat(" ", len(submatch(0))*6)#g<Cr> menu SpacesRefactoring.[Tab\ to\ 8\ Spaces] :%s#^\(\t\+\)#\=repeat(" ", len(submatch(0))*8)#g<Cr>
nmap <F2> :emenu SpacesRefactoring.<Tab>
- Нажатие F2 вызовет меню из нескольких пунктов, где можно выбрать, сколько пробелов конвертировать в табы и наоборот, привести табы к несокльким пробелам.
Имена объектов
- Имена локальных переменных или членов класса должны состоять только из строчных букв, и не содержать сокращений. Несколько слов в названии переменной должны разделятся символом прочерка (_), но не использованием строчной буквы.
# Неправильно:
bigRedBall = 4 my_fnct = lambda : None
# Правильно: big_red_ball = 4
my_func = lambda : None
- Допускается использование общепринятых и распространенных и сокращений, таких, как count, func, err, ptr, const, iter и других. Сокращений, типа intern_err_lvl (internal_error_level) следует избегать.
- Следует избегать названий переменных, состоящий из одной буквы, таких, как i, j, x, y, однако допускается использование их для определения однозначно ассоциируемых понятий, таких, как координаты на плоскости. В случае, если вы хотите использовать такую переменную как счетчик внутри цикла, к ее имени следует добавлять постфикс "_count".
# Неправильно:
x = 0 while x < 5 : pass # Некоторый код...
# Правильно: x_count = 0 while x_count < 5 :
pass # Некоторый код...
- При использовании переменной в качестве элемента итерации или для обозначения ее вида следует использовать постфиксы "_list", "_item", "_dict", "_key", "_flag" (для булевых переменных) и некоторые другие. Если переменная представляет собой экземпляр класс, в терминологии библиотеки являющегося типом, то нужно подписывать другие постфиксы, например, для объекта QWidget в Qt имя будет состоять из нескольких слов плюс постфикс "_widget". Типы QList и QStringList будут иметь одинаковый постфикс "_list", поскольку оба могут быть итерируемы. Элемент итерации для этих типов должен состоять из полного названия объекта плюс префикса "_item", например, "servers_list" и "servers_list_item".
- Исключением можно считать элемент, который сам по себе является более сложным типом данных, например, виджетом. Имя такого элемента определяется произвольным образом с учетом остальных правил и не оканчивается суффиксом "_item".
# Неправильно:
for i in strings_list : pass # Правильно: for strings_list_item in strings_list : pass
- Недопускается объявление разных переменных в одну строчку, однако разрешается присваивание одного значения нескольким переменным.
# Неправильно:
first = 0; last = 5 begin = 0; end = 5;
# Правильно: first = begin = 0
last = end = 5
- Такой код можно использовать только в том случае, когда переменные логически близки друг к другу и только при объявлении. Счетчики надо объявлять отдельно.
- Глобальные переменные нужно именовать строчными буквами, начиная каждое слово с прописной буквы. Аббревиатуры в именах таких переменных так же следует именовать исходя из этого правила, то есть, большая буква будет только в начале слова.
# Неправильно:
XMLHandler_Default = None
# Правильно:
DefaultXmlHandler = None
- Допускается использование прочерка, в случае, если одна часть имени переменной отражает одну логическую составляющую, а друга часть - другую:
F1_Key = 1
F2_Key = 2 Return_Key = 3
- В Python отсутствует такая возможность, как объявление макросов в стиле C или констант C++, поэтому, для создания глобальных (на модуль) констант нужно использовать имена, состоящие из прописныз букв, разделенных подчеркиваниями:
LIBS_DIR_PATH = "/usr/lib"
- Имена классов и метаклассов должны состоять из нескольких слов, каждая первая буква каждого слова должна быть прописной.
# Неправильно:
class foo_bar(object) : pass
# Правильно: class FooBar(object) :
pass
- Имя функции члена-класса или просто функции модуля должно состоять из строчных букв, начинающихся с прописных. Первая буква имени функции должна быть строчной.
# Неправильно:
def some_function() : pass
# Правильно: def someFunction() :
pass
- Исключение: если одна функция/класс вложена в другую (т.е. замыкание), то внутренняя функция/класс считается локальной переменной и именуется в соответствии с правилами для переменных.
- Для переменных-членов класса используйте имена, начинающиеся с "_" и "__". Первое обозначает, что переменная является закрытой, но ее переназначение допускается при наследовании. Второй тип переменных является полностью закрытым и используется только ввнутри класса родителя, не пересекаясь с дочерним классом, переменная в котором может иметь точно такое же имя.
- Не используйте "_" и "__" для имен функций и классов. Группируйте их по признаку доступа визуально и указывайте комментарий "# Public", "# Private", "Handlers" и другие. Подробнее тут.
Разделители
- Используйте одну пустую строку для логического разделения процедур.
- Используйте две пустых строки для логического разделения закрытых/открытых функций/переменных/классов на модуль или класс. Сначала пишите группу закрытых объектов, затем группу публичных.
- Операторы присвоения, логические операторы и любые другие нужно разделять пробелами.
- Перед символом ":" обозначающим начало блока, нужно ставить один пробел.
Неправильно:
def more(x): return x**2 f = lambda a: more(a)
Правильно: def more(x) : return x ** 2
func = lambda more(a) : a
Использование скобок
- Группируйте скобками операции независимо от действия приоритета.
# Неправильно:
if a or b and c : pass
# Правильно: if a or (b and c) : pass
# Неправильно: x = a or b and c
# Правильно:
x_flag = a or (b and c)
- По обеим сторонам от внутреннего содержимого скобок не нужно ставить пробелы. Исключения составляют lambda-функции, строчные операторы if-else, и заполнение списка.
dir_list = [ item for item in os.listdir(".") if item[0] != "." ]
pow = ( lambda x, n : x ** n )
line = ( "foo" if True else "bar" )
- Круглые скобки не нужно указывать, если выражение является единственным вложенным аргументом других скобок. Наличие отступов сохраняется.
foo( "foo" if True else "bar" ).
- Используйте пробелы внутри скобок и табуляцию каждой строки, если содержимое занимает несколько строк, для всех операторов, кроме вызовов функций и конструкторов.
- В остальном, ставьте скобки только там, где они действительно нужны.
Комментарии
- Комментарии должны начинаться с символа "#", имеющего после себя один пробел. Комментарии больше длиннее 5 строк должны начинаться и заканчиваться специальной последовательностью """ для многострочных комментариев (docstring) Python.
Исключения
- Допускаются любые исключения, если ваш код с использованием вышеописанных правил выглядит не очень хорошо или же здравый смысл подсказывает, что правило в данном случае не подходит. Красота кода остается главным критерием этого кодинг-стайла.