Чем больше становится проект, тем сильнее он нуждается с средствах форматирования, поскольку код разнообразный код сложнее поддерживать. Мы уже говорили о таком руководстве по форматированию Python-кода, как PEP 8. Сегодня рассмотрим способ форматирования под названием Black, который знаменит своей строгостью. В этой статье вы узнаете о различиях между PEP 8 и Black и в чем преимущества последнего в больших проектах.
Основы форматирования кода с Black
Black во многом наследует принципы форматирования PEP 8. Всё, что касается пробелов на одной строке, остается таким же. Например, 4 пробела — это отступ, не нужно ставить пробелы вокруг скобок и т.д. А вот размещение самих строк уже отличается. Black рассматривает одно полное выражение или операторы на каждой строке.
На одной строке размещаются до 88 знаков, длинные выражения не в почете. Ставятся две пустые строки перед функциями и классами; одна строка перед методами одного класса. Пустая строка после документации функции нужна только в случае, если она содержит другую функцию (функция-декоратор). После документации класса обязательно должна стоять пустая строка, если после нее перечисляются поля или объявляется метод.
Еще одно важное замечание: строки размещаются в двойных кавычках ", а не в одинарных '. И это оправдано. Многие Python-разработчики в этом деле не очень последовательны: в одном проекте применяют оба вида кавычек.
По началу будет сложно привыкнуть к строгости Black, однако по мере роста кода вы ощутите его преимущества:
- постоянство (поскольку все очень строго и нет пространства для самовыражения);
- читаемость (к такому коду привыкаешь);
- удобство разработки (при использовании версий контроля уменьшаются размеры diff’ов).
Размещение строк
Если выражение короткое, то следует разместить его на одной строке:
j = [1, 2, 3]
Если же нет, то внутренние содержимое переводить на следующую строку. Ниже представлены правильный и неправильный Python-код с точки зрения Black.
# неправильно:
ImportantClass.important_method(exc, limit, lookup_lines, capture_locals, extra_argument)
# правильно:
ImportantClass.important_method(
exc, limit, lookup_lines, capture_locals, extra_argument
)
Если даже так получается длинное выражение, то применяется то же самое правило: переводится следующая строка для каждого содержимого. Например, аргументы функции размещаются на отдельных строчках:
def very_important_function(
template: str,
*variables,
file: os.PathLike,
engine: str,
header: bool = True,
debug: bool = False,
):
"""Applies `variables` to the `template` and writes to `file`."""
with open(file, "w") as f:
...
Обратите внимание, где стоит закрывающая скобка: на следующей строке. PEP 8 разрешал оставить её на последнем аргументе, но Black этого не допускает. Кроме того, PEP 8 разрешает размещать аргументы в виде таблицы, но Black категоричен — либо все на одной строке, либо каждый аргумент на отдельной. Поэтому следующий код на Python не соответствует философии Black:
# Такой код не "черный":
foo = long_function_name(var_one, var_two,
var_three, var_four)
# Поэтому 1. либо так:
func(one, two three, four)
# 2. либо так:
foo = long_function_name(
var_one, var_two, var_three, var_four
)
# 3. либо так:
foo = long_function_name(
var_one,
var_two,
var_three,
var_four
)
Данное правило также распространяется на импорт модулей.
# так:
from typing import (
Iterator,
List,
Sequence,
Set,
)
# или этак:
from typing import Iterator, List, Sequence, Set
Форматирование условий в соответствии с Black
Условия (if) и циклы (while) подчиняются тому же правилу: если выражение короткое, то не разделяется; если длинное, то разделяется. При длинном выражении сначала ставится открывающая скобка и затем перевод строки.
# Короткое выражение
# неправильно:
if some_short_rule1 \
and some_short_rule2:
# правильно:
if some_short_rule1 and some_short_rule2:
# Длинное выражение
# неправильно:
if some_long_rule1 \
and some_long_rule2:
# правильно:
if (
some_long_rule1
and some_long_rule2
):
Обратные слэши в “черном” коде не используются. Логические операторы в длинных выражениях переходят на следующую строку. Условия часто становятся длинными, поэтому, применяя форматирование Black, количество строк увеличивается, однако визуально Python-код становится более читаемым. Пример такого кода:
if (
leaf.value == "not"
and leaf.parent
and leaf.parent.type == syms.comp_op
and not (
previous is not None
and previous.type == token.NAME
and previous.value == "is"
)
):
return COMPARATOR_PRIORITY
Цепочки вызовов
Длинные выражения могут содержать вызовы методов, идущие друг за другом (особенно это заметно при использовании фреймворка Apache Spark). Так вот точка вместе с самим вызовом переносится на следующую строку без дополнительных отступов. Взгляните на следующий Python-код, который написан в соответствии с Black:
def example(session):
result = (
session.query(models.Customer.id)
.filter(
models.Customer.account_id == account_id,
models.Customer.email == email_address,
)
.order_by(models.Customer.id.asc())
.all()
)
В версиях кода с Black легче разобраться
При размещении закрывающей скобки на отдельной строке, не нужно с ней возиться при добавление нового кода. Например, сравните diff без использования Black:
@@ -114,7 +114,8 @@ class MouseMotionEvent(MotionEvent):
with win.canvas.after:
de = (
Color(.8, .2, .2, .7),
- Ellipse(size=(20, 20), segments=15))
+ Ellipse(size=(20, 20), segments=15),
+ Depth(.5))
self.ud._drawelement = de
if de is not None:
self.push()
и с его использованием:
@@ -115,6 +115,7 @@ class MouseMotionEvent(MotionEvent):
de = (
Color(.8, .2, .2, .7),
Ellipse(size=(20, 20), segments=15),
+ Depth(.5),
)
self.ud._drawelement = de
if de is not None:
Конечно, не обязательно знать все правила, поскольку инструмент форматирования Black можно встроить во многие текстовые редакторы. Инструкция по интеграции размещена в документации. О том, как писать грамотный и читаемый код на языке Python, вы узнаете на бесплатном курсе по машинному обучению «Основы языка Python для анализа данных и решения задач машинного обучения» в лицензированном учебном центре обучения и повышения квалификации разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве.



