Style Guide for Python

Содержание

  1. Цель руководства
  2. Внешний вид кода
  3. Общие правила написания кода
  4. Правила написания кода в проектах М3
  5. Правила написания кода в прикладных проектах

Цель руководства

Руководство является соглашением по оформлению и написанию кода. В руководстве приведены основные правила оформления и приемы, используемые при написании программ.

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

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

Код читается намного больше раз, чем пишется. Собственно, рекомендации о стиле написания кода направлены на то, чтобы улучшить читабельность кода и сделать его согласованным между большим числом проектов. В идеале, весь код будет написан в едином стиле, и любой сможет легко его прочесть. Как говорится в PEP 203 , «Читабельность имеет значение». Это руководство о согласованности и единстве. Согласованность с этим руководством очень важна. Согласованность внутри одного проекта еще важнее. А согласованность внутри модуля или функции — самое важное. Но важно помнить, что иногда это руководство неприменимо, и понимать, когда можно отойти от рекомендаций. Когда вы сомневаетесь, просто посмотрите на другие примеры и решите, какой выглядит лучше. Две причины, чтобы нарушить правила: Когда применение правила сделает код менее читабельным даже для того, кто привык читать код, который следует правилам. Чтобы писать в едином стиле с кодом, который уже есть в проекте и который нарушает правила (может быть, в силу исторических причин).

Отступы

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

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

Ограничьте максимальную длину строки 79 символами. Ограничив ширину окна 80 символами, мы сможем расположить несколько окон рядом друг с другом. Так что, пожалуйста, ограничьте длину строки 79 символами, и 72 символами в случае длинных блоков текста (строки документации или комментарии). Предпочтительный способ переноса длинных строк — использование подразумевающегося продолжения строки между обычными, квадратными и фигурными скобками. В случае необходимости, можно добавить еще одну пару скобок вокруг выражения. Не используйте обратный слэш. Предпочтительнее вставить перенос строки после бинарного оператора, но не перед ним. Не используйте тернарные операторы, если строка, в которой он используется, требует переноса. При переносе строк выравнивайте их по вертикали, как показано в примере, или оставьте один уровень отступа в 4 пробела, если в первой строке нет ни одного аргумента.

Правильно:

# Выравнивание по вертикали
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# Отступ в 4 пробела; ничего на первой строчке
foo = long_function_name(
    var_one, var_two, var_three,
    var_four)

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

# Есть аргументы на первой линии
foo = long_function_name(var_one, var_two,
    var_three, var_four)

# Отступы в 2 пробела запрещены
foo = long_function_name(
  var_one, var_two, var_three,
  var_four)

Еще пример как правильно:

class Rectangle(Blob):
    def __init__(self, width, height,
                 color='black', emphasis=None, highlight=0):
        if (width == 0 and height == 0 and
                color == 'red' and emphasis == 'strong' or
                highlight > 100):
            raise ValueError("sorry, you lose")
         if width == 0 and height == 0 and (color == 'red' or
                                            emphasis is None):
            raise ValueError("I don't think so -- values are %s, %s" %
                             (width, height))
         Blob.__init__(self, width, height,
                       color, emphasis, highlight)

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

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

Пробелы

Не используйте пробелы в следующих ситуациях:

  • Сразу после или перед скобками (обычными, фигурными и квадратными):

    spam(ham[1], {eggs: 2}) #  Правильно
    spam( ham[ 1 ], { eggs: 2 } ) #  Неправильно
    
  • Сразу перед запятой, точкой с запятой, двоеточием:

    if x == 4: print x, y; x, y = y, x #  Правильно
    if x == 4 : print x , y ; x , y = y , x #  Неправильно
    
  • Сразу перед открывающей скобкой, после которой начинается список аргументов при вызове функции:

    spam(1) #  Правильно
    spam (1) #  Неправильно
    
  • Сразу перед открывающей скобкой, после которой следует индекс или срез:

    dict['key'] = list[index] #  Правильно
    dict ['key'] = list [index] #  Неправильно
    
  • Использование более одного пробела вокруг оператора присваивания (или любого другого) для того, чтобы выровнять его с другим таким же оператором на соседней строке:

    # Правильно:
    x = 1
    y = 2
    long_variable = 3
    
    # Неправильно:
    x             = 1
    y             = 2
    long_variable = 3
    

А так же:

  • Всегда окружайте эти бинарные операторы одним пробелом с каждой стороны: Присваивание (=, +=, -= и прочие), сравнения (==, <, >, !=, <>, <=, >=, 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)
    
    # Неправильно:
    i=i+1
    submitted +=1
    x = x*2 - 1
    hypot2 = x*x + y*y
    c = (a+b) * (a-b)
    
  • Не используйте пробелы для отделения знака =, когда он употребляется для обозначения аргумента-ключа (keyword argument) или значения параметра по умолчанию:

    # Правильно:
    def complex(real, imag=0.0):
        return magic(r=real, i=imag)
    
    # Неправильно:
    def complex(real, imag = 0.0):
        return magic(r = real, i = imag)
    
  • Не используйте составные инструкции (несколько команд в одной строке):

    # Правильно:
    if foo == 'blah':
        do_blah_thing()
    
    for x in lst:
        total += x
    
    while t < 10:
        t = delay()
    
     # Неправильно:
    if foo == 'blah': do_blah_thing()
    else: do_non_blah_thing()
    
    try: something()
    finally: cleanup()
    
    do_one(); do_two(); do_three(long, argument,
                                 simple_list, like, this)
    
    if foo == 'blah': one(); two(); three()
    
  • В шаблонах django разделяйте одним (и только одним) пробелом фигурные скобки и содержимое тега:

    {{ foo }}
    

Import-секции

Импортирование разных модулей должно быть на разных строчках:

# Правильно:
import os
import sys

# Неправильно:
import os, sys

В то же время, можно писать вот так:

from subprocess import Popen, PIPE

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

Группируйте импорты в следующем порядке:

  • импорты стандартной библиотеки;
  • импорты сторонних библиотек;
  • импорты модулей текущего проекта.

Вставляйте пустую строку между каждой группой импортов.

Комментарии

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

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

Блок комментариев обычно состоит из одного или более абзацев, составленных из полноценных предложений, поэтому каждое предложение должно оканчиваться точкой. Блок комментариев обычно объясняет код (весь, или только некоторую часть), идущий после блока, и должен иметь тот же отступ, что и сам код. Каждая строчка такого блока должна начинаться с символа # и одного пробела после него (если только сам текст комментария не имеет отступа). Абзацы внутри блока комментариев лучше отделять строкой, состоящей из одного символа #.

Старайтесь реже использовать комментарии в строке с кодом. Такие комментарии должны отделяться хотя бы двумя пробелами от инструкции. Они должны начинаться с символа # и одного пробела.

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

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

Соглашения о написании хорошей документации (docstrings) увековечены в PEP-0257. Пишите документацию для всех модулей, функций, классов, методов, которые объявлены как public. Строки документации необязательны для не-public методов, но лучше написать, что делает метод.

Комментарий как строку документации нужно писать после строки def. PEP-0257 объясняет, как правильно и хорошо документировать код. Заметьте, очень важно, чтобы закрывающие кавычки """ стояли на отдельной строчке. А еще лучше, если перед ними будет ещё и пустая строка. Для однострочной документации можно оставить """ на той же строке.

Именование

Стили имен

Обычно различают следующие стили:

  • b - одиночная маленькая буква
  • B -одиночная заглавная буква
  • lowercase - слово в нижнем регистре
  • lower_case_with_underscores - слова из маленьких букв с подчеркиваниями
  • UPPERCASE - заглавные буквы
  • UPPERCASE_WITH_UNDERSCORES - слова из заглавных букв с подчеркиваниями
  • CapitalizedWords -слова с заглавными буквами, или CapWords, или CamelCase. Иногда называется StudlyCaps. Замечание: когда вы используете аббревиатуры в таком стиле, пишите все буквы аббревиатуры заглавными — HTTPServerError лучше, чем HttpServerError.
  • mixedCase - отличается от CapitalizedWords* тем, что первое слово начинается с маленькой буквы
  • Capitalized_Words_With_Underscores - слова с заглавными буквами и подчеркиваниями — уродливо!

В дополнение к этому, используются следующие специальные формы записи имен с добавлением символа подчеркивания в начало или конец имени:

  • _single_leading_underscore - слабый индикатор того, что имя используется для «внутренних нужд». Например, from M import * не будет импортировать объекты, чьи имена начинаются с символа подчеркивания.
  • single_trailing_underscore_ - используется по соглашению для избежания конфликтов с ключевыми словами языка python, например: Tkinter.Toplevel(master, class_='ClassName')
  • __double_leading_underscore__ - изменяет имя атрибута класса, т.е. в class FooBar поле __boo становится _FooBar__boo.
  • __double_leading_and_trailing_underscore__ - двойное подчеркивание в начале и в конце имени. Это «магические» объекты или атрибуты, которые «живут» в пространствах имен, управляемых пользователем (user-controlled namespaces). Например, __init__, __import__ или __file__. Не изобретайте такие имена, используйте их только так, как написано в документации.

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

Никогда не используйте символы l (маленькая латинская буква «эль»), O (заглавная латинская буква «о») или I (заглавная латинская буква «ай») как однобуквенные идентификаторы. В некоторых шрифтах эти символы неотличимы от цифры один и нуля (и символа вертикальной палочки). Более того плохо использовать однобуквенные переменные за исключением в качестве счетчиков i, j и так далее.

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

Модули должны иметь короткие имена, состоящие из букв нижнего регистра. Можно использовать и символы подчеркивания, если это улучшает читабельность. То же, за исключением символов подчеркивания, относится и к именам пакетов. Так как имена модулей отображаются в имена файлов, а некоторые файловые системы являются нечувствительными к регистру символов и обрезают длинные имена, очень важно использовать достаточно короткие имена модулей — это не проблема в Unix, но, возможно, код окажется непереносимым в старые версии Windows или Mac, или DOS. Когда модуль расширения, написанный на С или C++, имеет сопутствующий python-модуль (содержащий интерфейс высокого уровня), С/С++ модуль начинается с символа подчеркивания, например, _socket.

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

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

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

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

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

Будем надеяться, что такие имена используются только внутри одного модуля. Руководствуйтесь теми же соглашениями, что и для имен функций. Добавляйте в модули, которые написаны так, чтобы их использовали с помощью from M import *, механизм all чтобы предотвратить экспортирование глобальных переменных. Или же, используйте старое соглашение, добавляя перед именами таких глобальных переменных один символ подчеркивания, которым вы можете обозначить те глобальные переменные, которые используются только внутри модуля.

Имена функций

Имена функций должны состоять из маленьких букв, а слова разделяться символами подчеркивания — это необходимо, чтобы увеличить читабельность. Стиль mixedCase допускается в тех местах, где уже преобладает такой стиль, например во threading.py, для сохранения обратной совместимости.

Аргументы функций и методов

Всегда используйте self в качестве первого аргумента метода экземпляра объекта (instance method). Всегда используйте cls в качестве первого аргумента метода класса (class method). Если имя аргумента конфликтует с зарезервированным ключевым словом python, обычно лучше добавить в конец имени символ подчеркивания, чем исказить написание слова или использовать аббревиатуру.

Таким образом, print_ лучше, чем prnt, возможно, хорошим вариантом будет подобрать синоним. Не сокращайте названия параметров request и context в методах обработки запросов, например, в django views или m3.Action.

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

Используйте тот же стиль, что и для имен функций - имена должны состоять из маленьких букв, а слова разделяться символами подчеркивания, чтобы избежать конфликта имен с подклассами. Добавьте два символа подчеркивания, чтобы включить механизм изменения имен. Если класс Foo имеет атрибут с именем __a, к нему нельзя обратиться, написав Foo.__a. Настойчивый пользователь всё равно может получить доступ, написав Foo._Foo__a.

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

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

Константы

Константы обычно объявляются на уровне модуля и записываются только заглавными буквами, а слова разделяются символами подчеркивания. Например: MAX_OVERFLOW, TOTAL.

Проектирование наследования

Обязательно решите, каким должен быть метод класса, атрибут — публичный public или не публичный protected. Если вы сомневаетесь, выберите закрытый, protected атрибут. Потом будет проще сделать их public, чем наоборот.

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

Мы не используем термин «закрытый член» (private), потому что на самом деле в python таких членов не бывает.

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

Когда вы проектируете такой класс, решите и явно укажите, какие атрибуты являются открытыми public, какие принадлежат API подклассов (subclass API), а какие используются только базовым классом.

Общие рекомендации

  • public атрибуты не должны иметь в начале имени символа подчеркивания

  • Если имя public атрибута конфликтует с ключевым словом языка, добавьте в конец имени один символ подчеркивания. Это более предпочтительно, чем аббревиатура или искажение написание. Однако, у этого правила есть исключение: первый аргумент метода класса (class method) должен иметь имя cls.

  • Назовите простые public атрибуты понятными именами и не пишите сложные методы доступа и изменения (accessor/mutator, get/set). Помните, что в python очень легко добавить их потом, если потребуется. В этом случае используйте свойства (properties), чтобы скрыть функциональную реализацию за синтаксисом доступа к атрибутам. Но не злоупотребляйте этим.

  • Свойства (properties) работают только в классах нового стиля (new-style classes)

  • Постарайтесь избавиться от побочных эффектов, связанных со сторонними эффектами (side effects). Впрочем, такие вещи, как кэширование, вполне допустимы.

  • Избегайте использования вычислительно затратных операций в setter'e properties, потому что из-за записи с помощью атрибутов создается впечатление, что доступ происходит (относительно) быстро.

  • Будьте внимательны: если подкласс будет иметь то же имя класса и имя атрибута, то вновь возникнет конфликт имен.

  • Механизм изменения имен может затруднить отладку или работу с __getattr__(), однако он хорошо документирован и легко реализуется вручную. Не всем нравится этот механизм, поэтому старайтесь достичь компромисса между необходимостью избежать конфликта имен и возможностью доступа к этим атрибутам.

В заключение

Таблица именования атрибутов в зависимости от контекста использования:

Type Public Internal
Packages lowercase
Modules lowercase
Classes CapWords _CapWords
Functions lower_with_under() _lower_with_under()
Global/Class Constants CAPS_WITH_UNDER _CAPS_WITH_UNDER
Global/Class Variables lower_with_under _lower_with_under
Instance Variables lower_with_under _lower_with_under (protected) or __lower_with_under (private)
Method Names lower_with_under _lower_with_under (protected)
Function/Method Parameters lower_with_under
Local Variables lower_with_under()

Описание моделей Django

Так как соглашение о стиле кода в Django не ограничивает длину строки 80 символами, то в описаниях моделей допустимо не переносить строки.

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

Порядок описания методов и подклассов модели должен быть следующим (учитывая, что они не все необходимые):

  • описание полей
  • пользовательские атрибуты менеджера
  • class Meta
  • def __unicode__()
  • def __str__()
  • def save()
  • def get_absolute_url()
  • другие пользовательские методы

При описании атрибутов модели не используйте имена зарезервированные БД (postgres, mysql и т.д.) такие как: date, string, datetime, number и т.д.

Также нежелательно использовать в качестве имен встроенные функции python (type, unicode и т.д.). Так как повышается вероятность того, что в дальнейшем при назначении этих атрибутов будут перекрыты питоновские функции. Особенно часто такое происходит с id и type.

Всегда указывайте verbose_name поля и модели. Просто так не используйте null=True, blank=True, если это не необходимо. Особенно в ForeignKey, за исключением, когда ссылка может быть пустой.

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

Общие правила написания кода

Импорты

Старайтесь не использовать относительные имена в импорте. Это помогает предотвратить непреднамеренный импорт пакетов в два раза.

from module import * сильно загрязняет пространство имен. Вы обнаружите объекты в вашем локальном пространстве имен, которые не ожидали получить. Вы можете увидеть имена, переопределяющие локальные, определенные ранее в модуле. Вы не сможете вычислить, откуда именно берутся эти имена. Хотя эта форма коротка и проста, ей не место в конечном коде.

Значительно лучше:

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

Импортируйте общедоступные методы и классы пакета в __init.py__. Таким образом, пакет должен предоставлять некий API для работы с ним, а реализацию инкапсулировать внутри себя. Соответственно, дальнейшее импортирование имен из модулей пакета считается плохим тоном.

Исключения

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

class MessageError(Exception):
    """Base class for errors in the email package."""

Здесь применимы те же правила, что и для именования классов. Если исключение по своему смыслу является ошибкой, вы можете добавить в конце имени Error. Когда вы генерируете исключение, пишите raise ValueError('message') вместо старого синтаксиса raise ValueError, message.

Когда код перехватывает исключения, «ловите» конкретные ошибки вместо простого выражнения except. К примеру, пишите вот так:

try:
    import platform_specific_module
except ImportError:
    platform_specific_module = None

Простое написание except: также перехватит и SystemExit, и KeyboardInterrupt, что породит проблемы, например, сложнее будет завершить программу нажатием Control+C. Если вы действительно собираетесь перехватить все исключения, пишите except Exception:, однако следует всегда перехватывать только те исключения, которые вы хотите отлавливать указывая их явно.

Ограничьтесь использованием чистого except: в двух случаях:

  1. Если обработчик исключения выводит пользователю всё о случившейся ошибке(например, traceback)
  2. Если нужно выполнить некоторый код после перехвата исключения, а потом вновь «бросить» его для обработки где-то в другом месте. Обычно же лучше пользоваться конструкцией try...finally.

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

# Правильно
try:
    value = collection[key]
except KeyError:
    return key_not_found(key)
else:
    return handle_value(value)

# Неправильно
try:
    # Здесь много действий!
    return handle_value(collection[key])
except KeyError:
    # Здесь также перехватится KeyError, сгенерированный
    # handle_value()
    return key_not_found(key)

Строки

Не делайте так:

result = ''
for s in colors:
      result += s

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

result = ''.join(colors)

Метод строк join() делает все копирования в один проход, один раз создавая объект строки.

Пользуйтесь ''.startswith() и ''.endswith() вместо обработки частей строк (string slicing) для проверки суффиксов или префиксов. startswith() и endswith() выглядят чище и порождают меньше ошибок. Например:

if foo.startswith('bar'): #  Правильно
if foo[:3] == 'bar': #  Неправильно

Когда вы проверяете, является ли объект строкой, обратите внимание на то, что строка может быть unicode-строкой. У str и unicode есть общий базовый класс - basestring.

Итераторы и операторы по умолчанию

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

# Правильно
for key in adict: ...
if key not in adict: ...
if obj in alist: ...
for line in afile: ...

# Неправильно
for k, v in dict.iteritems(): ...
for key in adict.keys(): ...
if not adict.has_key(key): ...
for line in afile.readlines(): ...

Проверка на истинность значения

Для последовательностей (строк, списков, кортежей) можно использовать тот факт, что пустая последовательность есть false:

# Правильно
if not seq:
if seq:

# Неправильно
if len(seq):
if not len(seq):

Не сравнивайте логические типы с True и False с помощью ==:

if greeting: #  Правильно
if greeting == True: #  Неправильно

А вот так писать совсем плохо:

if greeting is True:

Правильное использование переменных

В переменных строго следует использовать значения одного типа, например, если переменная содержит словарь, то по определенному условию она не может содержать другие типы данных, за исключением None (в контексте словаря лучше использовать {} - пустой словарь, исключением являются значения по-умолчанию, рассмотренные ниже).

Что касается экземпляров объектов, то переменная либо содержит его экземпляр, либо экземпляр не содержит, в таком случае переменная должна содержать значение None. Переменные булевого типа не должны содержать никаких иных значений, отличных от True/False.

Значения параметров по-умолчанию

def bad_append(new_item, a_list=[]):
    a_list.append(new_item)
    return a_list

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

Попробуйте вот это несколько раз:

>>> bad_append('one')
['one']
>>> bad_append('two')
['one', 'two']

Списки — изменяемые объекты, вы можете изменить их содержимое. Правильный способ получить список «по-умолчанию» (или словарь, или множество) — создать его во время выполнения, а не в объявлении функции:

def good_append(new_item, a_list=None):
    if a_list is None:
        a_list = []
    a_list.append(new_item)
    return a_list

Так же неправильно использовать любые изменяемые параметры в функции/методе, например:

import datetime
def bad_example(date=datetime.datetime.now()):
    pass

Написание запросов на Django ORM

Нельзя использовать QuerySet внутри условий, т.к. при этом происходит полное выполнение запроса и загрузка данных на сторону питона. Пример:

query = Users.objects.filter(name=u'Паша')
if query: # Плохо! Сгенерируется запрос в БД и выберутся все Паши
if query.count(): # Плохо! Будут посчитаны все Паши.
                  # Сервер будет читать все записи запроса и заблокирует их до полного расчета

if query.exists(): # Хорошо! Будет выбран только id первой записи
if query is None: # Хорошо! Проверка на тип значения, когда переменную надо проверить на пустоту

Часто пишут получение единственной записи через get по условиям (не по конкретному первичному ключу), при этом не обращая внимания на возможные ошибки: записи может не быть и записей может быть несколько.

# Плохо:
ae = AccountEntry.objects.get(operation=self.op, block=block)

# Лучше:
try:
    ae = AccountEntry.objects.get(operation=self.op, block=block)
except AccountEntry.DoesNotExist:
     ae = AccountEntry()
ae.summa = 0

# Совсем хорошо:
try:
    ae = AccountEntry.objects.get(operation=self.op, block=block)
except AccountEntry.DoesNotExist:
    ae = AccountEntry()
except AccountEntry.MultipleObjectsReturned:
    # тут надо что-то решать с дублированием
    raise
ae.summa = 0

Правила написания кода в проектах М3

Разработка UI

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

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

Начните имя новых полей с field_ для всех полей формы, которые передают значения.

# Хорошо
field_name = ExtStringField().

# Плохо
name = ExtStringField().

South

Если вам нужно обратиться к модели внутри миграции используйте orm. Пример: orm.Children.objects.all(). Таким образом будет получена модель по состоянию на момент написания миграции. Если вы явно используете импорт модели из model.py - то получите последнее возможное состояние модели, которое будет отличаться от таблицы в БД.

Прочее

Удаляйте не нужные куски кода, а не оставляйте их закомментированными! Кроме временного комментирования, которое гарантировано будет убрано в будущем. Оставленый закомментированным код, который вы “постеснялись” удалить, будет мешать остальным разработчикам, вызывая лишние вопросы.

Методы должны иметь одну точку выхода, один return.

Правила написания кода в прикладных проектах

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

Contents © 2014 БАРС Груп - Powered by Nikola