# Python Style Guide Этот раздел отвечает за то, как должен выглядеть код на Python. ## Форматирование кода Отступ: 4 пробела. Максимальное количество символов на строку: 80. Максимальное количество символов на doc-string: 72. Количество пустых строк между функциями: - вне класса — 2; - в классе — 1. Количество пустых строк между классами: 2 Количество пустых строк после импорта зависимостей: 2. Не оставляйте "повисших" запятых. Пример "повисшей" запятой: ```python [ path('question/all/', QuestionListApiView.as_view()), path('question/group/all/', QuestionGroupListApiView.as_view()), path('question/block/all/', QuestionBlockListApiView.as_view()), ] ``` Эта запятая тут явно не нужна. Избегайте таких моментов. Файл должен кончаться пустой строкой. Весь код в MR будет проверяться ровно по этому формату. Если он не будет ему соответствовать — MR будет отправлен на доработку. ## Переменные Каждая переменная должна чётко отражать то значение, которое в ней будет находиться. Все булевые (флаговые) переменные начинаются с префикса «is», например: «is_active». В идеале, всё должно прийти к тому состоянию, когда мы во всех местах имеем флаги, которые будут работать одинаково и принимать значения True/False внезависимости от того, в каком месте кода они используются. Все переменные для подсчёта чего-либо должны иметь постфикс «count», например: «experts_count». Мы должны стремиться к декларативности и читаемости, поэтому каждая переменная должна быть обдуманной. Все значения строковых переменных должны браться в **двойные кавычки**. Все константные переменные набираются в верхнем регистре. ## Интерполяция строк Поскольку подход к интерполяции строк надо унифицировать будем использовать f-строки. Пример интерполяции строк с использованием f-строк: ```python HOURS_A_DAY = 24 message = f"We have only {HOURS_A_DAY} hours..." ``` Складывать строки запрещено. Можно пользоваться только интерполяцией. ## Условия По-хорошему, в условиях избегать двух вещей: 1) [Магических значений](https://ru.hexlet.io/blog/posts/magic-numbers) 2) Прямых сравнений в самом условии. Что я под этим подразумеваю? Я предлагаю заводить отдельную булевую переменную, которая будет использоваться в условии. Пример хорошего условия: ```python HOURS_A_DAY = 24 current_hours = 23 is_day_over = current_hours == HOURS_A_DAY if is_day_over: ... ``` ## Функции Название каждой функции должно чётко отражать суть самой функции. Не должно возникать ситуаций, когда нужно прочесть всю функцию, чтобы понять, для чего она нужна. Получение, изменение и отображение — это три разных функции. Функция получения/изменения каких-то параметров должна возвращать конечный результат — изменённые параметры. Функция отображения должна обращаться к функциям получения/изменения и отображать эти изменения. Никаких неявных преобразований. Входные и выходные параметры всех функций должны быть описаны по pydoc. Пример есть [тут](https://pythonchik.ru/osnovy/dokumentirovanie-koda-v-python). Кроме того, должны быть обозначены типы для входных и выходных параметров функции, пример: ```python def _get_hash(self, _code: int) -> str: # переведём в строку code = str(_code) # переведём в bytes code = code.encode() # переведём в hash _hash = md5(code) return _hash.hexdigest() ``` Помните, что каждая функция должна выполнять одну **небольшую** задачу. ## Классы Если вы заводите класс, то его методы должны быть именно **его** методами. Они не должны работать как обычные функции. Вы должны предусмотреть какую-то стандартную конфигурацию для класса. Пользуйтесь плюсами ООП и не забывайте про наследование: хорошо, когда у вас есть базовый класс для взаимодействия с чем-либо, но если вы хотите его **расширить**, то стоит подумать насколько тот метод, который вы хотите добавить является **необходимым** для базового класса. Если он не является таковым, то вписывайте этот метод в новый экземпляр класса, который будет являться расширением для базового класса. Требования по неймингу такие же, как и для переменных и функций. ## TODO и FIXME В коде стоит разделять задачи, которые вы хотите зафискировать во время процесса на TODO — что предстоит сделать и FIXME — что предстоит исправить. Обе подобные метки означают, что вы заводите техдолг. Вы должны обозначить, кроме прочего, что техдолг принадлежит вам. Пример: ```python # TODO: 02.04.21, Родион # написать метод для получения списка конкурсов ``` ## Git Каждая отдельная задача — отдельная ветка, которая удаляется после закрытия задачи. Каждый коммит — законченная мысль. Шаг к выполнению задачи. Один коммит приходится на одно изменение. То есть изменение трёх функций — это три коммита (но, например, если ты меняешь название метода, то логично, что следом в этом же коммите название этого метода должно измениться во всех местах, где он вызывается). Таким образом мы всегда сможем нормально откатиться к любой интересующей нас версии проекта. Сообщения коммитов пишутся в нормальной форме, например: Add src/components/NewFile.vue. Цикл разработки должен прийти к следующему состоянию: feature, refactoring, documentarion, fixing. Каждый коммит должен начинаться с соответствующего префикса: «[feat]», «[ref]», «[doc]», «[fix]». Названия веток подчиняются следующему правилу: `{project}-{issue_number}--{service_slug}` Где в качестве service_slug выступает конкретный репозиторий того или иного проекта. Примеры service_slug: 1) QS - questionnaire-service 2) RB - refbook-service 3) QWT - questionnaire-wagtail Пример названия ветки: `EXAMPLE-9--RB`