Project

General

Profile

Требования к организации и оформлению кода (Python)

Концептуальные требования

  • Система классов программы должна быть осмысленной и отвечать парадигме объектно-ориентированного программирования.

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

  • Категорически запрещается дублирование одинакового кода!

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

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

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

  • Все возможные ошибочные ситуации должны корректно обрабатываться. Сообщения об ошибках должны быть максимально информативными.

  • Сравнение с None должно осуществляться только с помощью операции is:

if x is None and z is not None:
     pass

Внешний вид кода

  • Используйте 4 пробела на один уровень отступа. Символы табуляции запрещены.

  • Ограничьте максимальную длину строки 90 символами.

  • В случае если строка больше 90 символов, осуществите перенос на новую строку с двойным отступом относительно текущего отступа.

  • Отделяйте функции верхнего уровня и определения классов двумя пустыми строками. Определения методов внутри класса отделяйте одной пустой строкой.

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

  • При импорте имён из модулей с помощью инструции from запрещается использовать форму со звёздочкой.

Соглашения по именам

  • Имена должны быть осмысленными словами (или словосочетаниями в значении соответствующей части речи) английского языка. Для локальных переменных допускается использование сокращённых имён (например, i) с сохранением общепринятого контекста (i только для управляющей переменной цикла).

  • Имена пакетов и модулей — существительные в нижнем регистре, слова разделяются подчёркиваниями (program_installer).

  • Имена классов — существительные или словосочетания в значении существительных: в нижнем регистре, первые буквы слов — в верхнем регистре, разделители слов не используются (ClientInfo); имена классов-исключений заканчиваются на Error (InvalidUserError).

  • Имена полей и локальных переменных — существительные в нижнем регистре, слова разделены подчёркиваниями (file_size).

  • Имена методов — глаголы в нижнем регистре (либо словосочетания, отражающие действия), слова разделены подчёркиваниями (remove_file). Для имён методов, возвращающих значения величин допускается использование существительных (например, volume вместо eval_volume), а не глаголов, если только это не приведёт к неоднозначности.

  • Имена констант — существительные или словосочетания в верхнем регистре, слова разделены подчёркиваниями (INVALID_RECORD_COLOR).

Пробелы в выражениях и инструкциях

  • Избегайте использования пробелов в следующих ситуациях:

    • Сразу после или перед скобками (круглыми, фигурными и квадратными)
spam(ham[1], {eggs: 2})
  • Сразу перед запятой, точкой с запятой, двоеточием:
if x == 4: print x, y; x, y = y, x
  • Сразу перед открывающей скобкой, после которой начинается список аргументов при вызове функции:
spam(1)
  • Сразу перед открывающей скобкой, после которой следует индекс или срез:
dict['key'] = list[index]
  • Всегда окружайте знаки бинарных операций одним пробелом с каждой стороны: присваивание (=, +=, -=, *= /=), сравнения (==, <, >, !=, <>, <=, >=, in, not in, is, is not), логические операции (and, or, not):
i = i + 1
submitted += 1 
x = x * 2 - 1 
hypot2 = x * x + y * y 
c = (a + b) * (a - b)
  • Используйте условную операцию if—else вместо оператора в тех случаях, когда соответствующее выражение умещается на одной строке. В противном случае используйте оператор if, размещая его ветви на отдельных строках:
result = "several" if len(list) > 1 else "zero or one"
if self.__draggedPath < MainView.__MIN_DRAG_PATH and not self._isButtonInside(*nextPos):
    result = 0
else:
    result = MainView.__MIN_DRAG_PATH + additionalDragPath * 2

Методы, поля и свойства классов

  • Используйте cls в качестве первого аргумента метода класса (class method).

  • Используйте self в качестве первого аргумента метода экземпляра объекта (instance method).

  • Имена частных методов должны начинаться с одного символа подчеркивания.

  • Все поля определяются частными (с префиксом из двух подчёркиваний).

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

from util.attribute import * # подключаем модуль с необходимыми функциями

class Person(object): # необходимо использовать new-style classes
    '''
    Basic descriptive object for typical person

    name: the name
    location: approximate location
    '''
    readable('name') # предоставляем доступ к атрибуту __name только на чтение
    writable('location') # предоставляем полный доступ к атрибуту __location

    def __init__(self):
        # инциализация атрибутов класса
        self.__name = 'Jone Dove'
        self.__location = 'New York'
        self.__bankAccount = '999-444-888-887'
        self.__job = 'Sales manager'

    def getJob(self):
        return self.__job;

    def employ(self, value):
        self.__job = value
        if value is None:
            self.__job = 'unemployed'

    # предоставляем нестандартный способ доступа к атрибуту __job
    job = property(getJob, employ, None, 'Place of employment')  

Пример доступа к свойствам и атрибутам класса Person:

person = Person()

# print person.__bankAccount # нельзя обращаться к частным атрибутам!

print person.name            # выводит на экран содержимое __name
# person.name = 'Mikle Russ' # нельзя выполнить присваивание

print person.location        # выводит на экран содержимое __address
person.location = 'London'   # можно выполнить присваивание

print person.job             # выводит на экран результат вызова getJob
person.job = None            # происходит вызов метода employ с аргументом value=None

Документирование кода

  • Обязательными являются документационные комментарии для всех модулей, классов, полей и методов.

  • !/images/smileys/fixme.gif! Как документировать поля классов? Epydoc или однострочные комментарии?

  • Для документирования следует использовать Epydoc и язык разметки Epytext #the-epytext-markup-language

  • Обязательно наличие тегов @type, @param, @return, @rtype, @raise для функций и методов (если они имеют соответствующие атрибуты):

def _parseRoot(root):
    '''
    Save XML tree information into mind map object

    @param root: XML tree root
    @type root: lxml Element

    @raise Exception: if no root node found

    @return: mind map object
    @rtype: MindMap
    '''
  • Если действие метода/функции тривиальное и его описание присутствует в теге @return, разрешается пропустить общий текст комментария к данному методу/функции:
@property
def allNodeAttributes(self):
    '''
    @return: list of pairs (attributeName, attributeValue) all node attributes
    @rtype: list
    '''
    return self.__nodeAttribute.attributesMap.items()
  • Если значение аргумента метода/функции понятно из его имени и имени самого метода/функции, разрешается пропустить тег @param. Чаще это исключения относится к методам классов, выполняющих тривиальные действия по получению/добавлению/установке значений полей:
def addChild(self, child):
    '''  
    Add a child node to the current node

    @type child: Node        
    '''
    self.__children.append(child)
  • Каждый модуль должен быть документирован в одном общем стиле (см. существующие модули проекта). Для создания исходных текстов может предоставляться специальный скрипт srccreate.

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

  • Комментарии должны быть только на английском языке.

  • Комментарии не должны содержать орфографических и пунктуационных ошибок.