Чем больше становится проект, тем сильнее он нуждается с средствах форматирования, поскольку код разнообразный код сложнее поддерживать. Мы уже говорили о таком руководстве по форматированию 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 в Москве.