---
# System prepended metadata

title: Python Style Guide

---

# 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`
