ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 03.12.2023
Просмотров: 378
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
72
Глава 3.Форматирование кода при помощи Black уверены, руководствуйтесь здравым смыслом». Независимо от того, собираетесь вы выполнять рекомендации полностью, частично или вообще никак, документ
PEP 8 стоит прочитать.
Так как мы используем систему форматирования Black, наш код будет следовать правилам руководства по стилю Black, которое было разработано согласно реко- мендациям PEP 8. Не поленитесь изучить эти рекомендации, потому что Black не всегда имеется под рукой. Рекомендации для форматирования Python, о которых я расскажу в этой главе, также применимы к другим языкам, для которых автома- тические системы форматирования не всегда доступны.
Мне не все нравится в том, как Black форматирует код, но это компромиссное ре- шение. Black использует правила форматирования, которые в целом устраивают программистов, чтобы они могли меньше тратить времени на споры и больше — на программирование.
Горизонтальные отступы
Для удобочитаемости вашего кода пустое место не менее важно, чем код, который вы пишете. Отступы помогают отделить обособленные части кода друг от друга, чтобы их было проще распознать. В этом разделе объясняются горизонтальные отступы — то есть пустые места в строке кода, в том числе в начале строки.
Использование пробелов для создания отступов
Для создания отступов в начале строки можно выбрать один из двух символов — пробел или табуляцию. И хотя годится любой вариант, для формирования отступов лучше использовать пробелы.
Дело в том, что эти символы ведут себя по-разному. Пробел всегда выводится на экран как строковое значение, состоящее из одного пробела —
'
'
. А символ табу- ляции, который выводится как строковое значение, содержащее служебный символ '\t'
, не столь однозначен. Символы табуляции часто (хотя и не всегда) выводятся как переменное количество пробелов, чтобы текст начинался со следующей позиции табуляции. Позиции табуляции устанавливаются через каждые восемь пробелов по ширине текстового файла. Этот вариант продемонстрирован в следующем примере, где слова сначала разделяются пробелами, а затем символами табуляции:
>>> print('Hello there, friend!\nHow are you?')
Hello there, friend!
How are you?
>>> print('Hello\tthere,\tfriend!\nHow\tare\tyou?')
Hello there, friend!
How are you?
Горизонтальные отступы
73
Так как символы табуляции представляют переменное количество пробелов, лучше не использовать их в исходном коде. Многие редакторы кода и IDE при нажатии клавиши TAB автоматически вставляют четыре или восемь пробелов вместо одного символа табуляции.
Также не следует смешивать пробелы и символы табуляции для создания от- ступов в одном блоке кода. Использование обоих символов настолько часто становилось причиной коварных ошибок в более ранних программах Python, что в Python 3 код с такими отступами даже не выполняется — выдается исклю- чение
TabError:
inconsistent use of tabs and spaces in indentation
(Непоследо- вательное применение табуляций и пробелов в отступах). Black автоматиче- ски преобразует все символы табуляции, используемые в отступах, в четыре пробела.
Что касается длины каждого уровня отступов, в Python один уровень обычно обо- значен четырьмя пробелами. В следующем примере пробелы для большей нагляд- ности помечены точками:
def getCatAmount():
....numCats = input('How many cats do you have?')
....if int(numCats) < 6:
........print('You should get more cats.')
Стандарт с четырьмя пробелами имеет практические преимущества перед другими альтернативами; в коде с восемью пробелами на уровень быстро возникает проблема ограничения длины строки, тогда как при уровне с двумя символами отступы не столь заметны. Программисты обычно не рассматривают другие значения (напри- мер, 3 или 6), потому что из-за привычки к двоичным вычислениям они предпо- читают работать со степенями двойки: 2, 4, 8, 16 и т. д.
Отступы в середине строки
Пробелы играют важную роль для визуального разделения разных частей кода.
Если вы их не используете, ваш код может оказаться слишком плотным и нераз- борчивым. В следующих подразделах я расскажу о некоторых полезных правилах при создании отступов.
Отделяйте операторы от идентификаторов одним пробелом
Если операторы и идентификаторы не разделены ни одним пробелом, создается впечатление, что ваш код выполняется подряд. Например, в следующей строке операторы и переменные разделены пробелами:
ДА:
blanks = blanks[:i] + secretWord[i] + blanks[i + 1 :]
74
Глава 3.Форматирование кода при помощи Black
А здесь все пробелы удалены:
НЕТ:
blanks=blanks[:i]+secretWord[i]+blanks[i+1:]
В обоих случаях оператор
+
используется для сложения трех значений, но без про- белов может показаться, что
+
в blanks[i+1:]
добавляет четвертое значение. Про- белы более наглядно показывают, что
+
является частью сегмента в значении blanks
Не ставьте пробелы перед разделителями, ставьте один пробел после разделителей
Элементы списков и словарей, а также параметры в определениях функций def разделяются запятыми. Не ставьте пробел перед этими запятыми, но поставьте один пробел после них, как в следующем примере:
ДА:
def spam(eggs, bacon, ham):
ДА:
weights = [42.0, 3.1415, 2.718]
В противном случае у вас получится перенасыщенный код, который плохо читается:
НЕТ:
def spam(eggs,bacon,ham):
НЕТ:
weights = [42.0,3.1415,2.718]
Не добавляйте пробелы перед разделителем, потому что этим вы привлекаете не- нужное внимание к символу-разделителю:
НЕТ:
def spam(eggs , bacon , ham):
НЕТ:
weights = [42.0 , 3.1415 , 2.718]
Black автоматически вставляет пробелы после запятых и удаляет пробелы перед ними.
Не ставьте пробелы до и после точек
Python разрешает вставлять пробелы до и после точек, отмечающих начало атрибу- тов Python, но делать этого не стоит. Таким образом вы подчеркиваете связь между объектом и его атрибутом, как в следующем примере:
ДА:
'Hello, world'.upper()
Если же поставить пробелы до или после точки, объект и атрибут выглядят так, словно они не связаны друг с другом:
НЕТ:
'Hello, world' . upper()
Black автоматически удаляет пробелы вокруг точек.
Горизонтальные отступы
75
Не ставьте пробелы после имен функций, методов и контейнеров
Имена функций и методов легко узнаваемы, потому что за ними следует пара круг- лых скобок. Не ставьте пробел между именем и открывающей круглой скобкой.
Обычно вызов функции записывается в следующем виде:
ДА:
print('Hello, world!')
С добавлением пробела единый вызов функции выглядит так, словно в коде идут два раздельных фрагмента:
НЕТ:
print ('Hello, world!')
Black удаляет все пробелы между именем функции или метода и его открывающей круглой скобкой.
По той же причине не ставьте пробел перед открывающей квадратной скобкой для индекса, сегмента или ключа. Обычно при обращении к элементам типа «контей- нер» (список, словарь или кортеж) пробел между именем переменной и открыва- ющей квадратной скобкой не ставится:
ДА:
spam[2]
ДА:
spam[0:3]
ДА:
pet['name']
Как и в предыдущем случае, при добавлении пробела этот код выглядит как два раздельных фрагмента:
НЕТ:
spam [2]
НЕТ:
spam [0:3]
НЕТ:
pet ['name']
Black удаляет все пробелы между именем переменной и открывающей квадратной скобкой.
Не ставьте пробелы после открывающих
и перед закрывающими скобками
Не должно быть пробелов, отделяющих круглые, квадратные или фигурные скобки от того, что внутри. Например, параметры в команде def или значения в списке должны начинаться и заканчиваться непосредственно после и перед круглыми и квадратными скобками:
ДА:
def spam(eggs, bacon, ham):
ДА:
weights = [42.0, 3.1415, 2.718]
76
Глава 3.Форматирование кода при помощи Black
Не ставьте пробел после открывающих или перед закрывающими круглыми и ква- дратными скобками:
НЕТ:
def spam( eggs, bacon, ham ):
НЕТ:
weights = [ 42.0, 3.1415, 2.718 ]
Добавление этих пробелов не делает код более удобочитаемым, поэтому они стано- вятся лишними. Black удаляет эти пробелы, если они присутствуют в вашем коде.
Ставьте два пробела перед комментариями в конце строки
Если вы добавляете комментарии в конце строки кода, поставьте два пробела между последним символом кода и символом
#
, начинающим комментарий:
ДА:
print('Hello, world!') # Вывод приветствия.
Два пробела помогают отделить код от комментария. С одним пробелом (или еще хуже — без пробелов) заметить комментарий будет трудно:
НЕТ:
print('Hello, world!') # Вывод приветствия.
НЕТ:
print('Hello, world!')# Вывод приветствия.
Black вставляет два пробела между последним символом кода и началом коммен- тария.
В общем случае я не рекомендую размещать комментарии в конце строки кода, потому что строка становится слишком длинной для чтения на экране.
Вертикальные отступы
Под вертикальными отступами понимается вставка пустых строк между строками кода. Подобно тому как разбивка текста книги на абзацы членит текст и способству- ет его правильному и быстрому восприятию, вертикальные отступы группируют строки кода и визуально отделяют группы друг от друга.
PEP 8 содержит ряд рекомендаций по вставке пустых строк в коде: руководство утверждает, что функции должны разделяться двумя пустыми строками, классы — двумя пустыми строками, а методы внутри класса — одной пустой строкой. Black автоматически следует этим правилам, вставляя или удаляя пустые строки в вашем коде. Например, фрагмент:
НЕТ:
class ExampleClass:
def exampleMethod1():
pass def exampleMethod2():
Вертикальные отступы
77
pass def exampleFunction():
pass преобразуется к следующему виду:
ДА:
class ExampleClass:
def exampleMethod1():
pass def exampleMethod2():
pass def exampleFunction():
pass
Пример использования вертикальных отступов
Однако Black не может решить, где должны располагаться пустые строки внутри ваших функций, методов или глобальной области видимости. Решение о том, какие из этих строк должны группироваться вместе, принимает программист.
Для примера рассмотрим класс
EmailValidator из файла validators.py фреймворка веб-приложений Django. Понимать, как работает этот код, необязательно. Обратите внимание на то, как пустые строки разделяют код метода
__call__()
на четыре группы:
def __call__(self, value):
if not value or '@' not in value:
❶
raise ValidationError(self.message, code=self.code)
user_part, domain_part = value.rsplit('@', 1)
❷
if not self.user_regex.match(user_part):
❸
raise ValidationError(self.message, code=self.code)
if (domain_part not in self.domain_whitelist and
❹
not self.validate_domain_part(domain_part)):
# Проверить возможные имена IDN
try:
domain_part = punycode(domain_part)
except UnicodeError:
pass else:
if self.validate_domain_part(domain_part):
return raise ValidationError(self.message, code=self.code)
78
Глава 3.Форматирование кода при помощи Black
Несмотря на отсутствие комментариев, описывающих эту часть кода, пустые строки показывают, что группы концептуально изолированы друг от друга. Первая группа
❶
проверяет символ
@
в параметре value
. Эта задача отличается от задачи второй группы
❷
, которая разбивает строку с адресом электронной почты из value на две новые переменные, user_part и domain_part
. Третья
❸
и четвертая
❹
группы используют эти переменные для проверки пользовательской и доменной части адреса электронной почты соответственно.
И хотя четвертая группа состоит из 11 строк (намного больше, чем в других груп- пах), все они решают одну задачу проверки домена из адреса электронной почты.
Если вы чувствуете, что в действительности здесь несколько подзадач, разделите их пустыми строками.
Программист, создававший эту часть Django, решил, что все строки проверки до- мена должны принадлежать одной группе, но другие программисты могут считать иначе. Так как это субъективное мнение, Black не изменяет вертикальные отступы внутри функций или методов.
Рекомендации по использованию вертикальных отступов
Python предоставляет одну возможность, о которой знают не все: точка с запятой
(
;
) может использоваться для разделения нескольких команд в одной строке. Это означает, что следующие две строки:
print('What is your name?')
name = input()
можно записать в одну, разделив их точкой с запятой:
print('What is your name?'); name = input()
Как и при использовании запятых, перед точкой с запятой пробел не ставится, а после ее ставится один пробел.
Для команд, завершающихся двоеточием (например, if
, while
, for
, def и class
), однострочный блок, как вызов print()
в следующем примере:
if name == 'Alice':
print('Hello, Alice!')
можно записать в одной строке с командой if
:
if name == 'Alice': print('Hello, Alice!')
Но хотя Python и разрешает разместить несколько команд в одной строке, это не считается хорошей практикой. Строки кода получаются слишком длинными
Black: бескомпромиссная система форматирования кода
79
и содержат слишком много информации, что затрудняет их восприятие. Black раз- бивает такие команды на отдельные строки.
Аналогичным образом можно импортировать несколько модулей одной командой import
:
import math, os, sys
Тем не менее PEP 8 рекомендует разбить эту команду на несколько коротких ко- манд, по одной для каждого модуля:
import math import os import sys
Если модули импортируются в отдельных строках, вам будет проще заметить любые добавления или удаления импортированных модулей при сравнении изменений функцией diff системы контроля версий (системы контроля версий, такие как Git, рассматриваются в главе 12).
PEP 8 также рекомендует объединять команды import в следующие три группы в указанном порядке.
1. Модули стандартной библиотеки Python: math
, os
, sys и т. д.
2. Сторонние модули: Selenium, Requests, Django и т. д.
3. Локальные модули, являющиеся частью программы.
Эти рекомендации не являются обязательными, и Black не изменяет форматиро- вание команд import в вашем коде.
1 2 3 4 5 6 7 8 9 ... 40
Black: бескомпромиссная система
форматирования кода
Black автоматически форматирует код в ваших файлах
.py
. Хотя вы должны по- нимать правила форматирования, рассмотренные в этой главе, Black выполняет всю работу по стилевому оформлению за вас. Если вы участвуете в совместном проекте, то можете моментально урегулировать многие споры относительно фор- матирования кода — просто поручите решение Black.
У нас нет возможности изменить многие правила, которым следует Black, поэтому
Black описывается как «бескомпромиссная система форматирования кода». Соб- ственно, его название (Black — черный) происходит от знаменитого высказывания
Генри Форда относительно цветов выпускаемых автомобилей: «Цвет автомобиля может быть любым, при условии что он черный».
80
Глава 3.Форматирование кода при помощи Black
Я описал конкретные стилевые правила, используемые Black; полное руководство по стилю для Black вы найдете по адресу https://black.readthedocs.io/en/stable/
the_black_code_style.html.
Установка Black
Установите Black при помощи программы pip
, входящей в комплект поставки
Python. В Windows для этого следует открыть окно командной строки и ввести команду:
C:\Users\Al\>python -m pip install --user black
В macOS и Linux откройте окно терминала и введите команду python3
вместо python
(это следует делать во всех фрагментах кода в этой книге, где используется команда python
):
Als-MacBook-Pro: al$ python3 -m pip install --user black
Ключ
-m приказывает Python запустить модуль pip как приложение (некоторые модули Python имеют соответствующую настройку). Чтобы убедиться в том, что установка прошла успешно, выполните команду python
-m black
. На экране должно появиться сообщение «
No paths given.
Nothing to do
» вместо «
No module named black
».
Запуск Black из командной строки
Black можно запустить для любого файла Python из командной строки или окна терминала. Кроме того, IDE или редактор кода позволяет запустить Black в фоновом режиме. Инструкции о том, как обеспечить работу Black с Jupyter Notebook, Visual
Studio Code, PyCharm и другими редакторами, вы найдете на домашней странице
Black по адресу https://github.com/psf/black/.
Допустим, вы хотите отформатировать файл с именем yourScript.py автоматически.
В командной строке Windows выполните следующую команду (в macOS и Linux используйте команду python3
вместо python
):
C:\Users\Al>python -m black yourScript.py
После выполнения этой команды содержимое yourScript.py будет отформатировано в соответствии с руководством по стилю Black.
Переменная среды
PATH
может быть уже настроена для прямого запуска Black.
В этом случае для форматирования yourScript.py достаточно ввести следующую команду:
C:\Users\Al>black yourScript.py
Black: бескомпромиссная система форматирования кода
81
Чтобы выполнить Black для каждого файла
.py в папке, укажите в команде папку вместо отдельного файла. Следующий пример Windows форматирует все файлы в папке
C:\yourPythonFiles
, включая ее вложенные папки:
C:\Users\Al>python -m black C:\yourPythonFiles
Передача папки пригодится в том случае, если ваш проект содержит несколько файлов Python и вы не хотите вводить отдельную команду для каждого файла.
Хотя Black довольно строго относится к форматированию кода, в следующих трех подразделах описаны некоторые параметры, которые вы можете настроить. Что- бы просмотреть полный набор ключей Black, выполните команду python
-m black
--help
Регулировка длины строки Black
Стандартная строка кода Python состоит из 80 символов. История 80-символьных строк уходит корнями в 1920-е годы, когда компания IBM представила перфокар- ты на 80 столбцов и 12 строк; 80-символьный стандарт стал использоваться для принтеров, мониторов и окон командной строки, появившихся через несколько десятилетий.
Но в XXI веке экраны с высоким разрешением позволяют выводить текст длиной более 80 символов. С большей длиной строки вам не придется выполнять верти- кальную прокрутку, чтобы просмотреть файл. С другой стороны, короткие строки не перегружены, а вы можете сравнить два исходных файла, разместив их на экране рядом друг с другом, без горизонтальной прокрутки.
Black по умолчанию использует строку длиной 88 символов. Выбор объясняется не очень убедительно: это на 10% больше стандартной 80-символьной строки.
Лично я предпочитаю 120 символов. Чтобы приказать Black форматировать код с 120-символьной (например) строкой, используйте ключ командной строки
-l
120
(буква l в нижнем регистре, не цифра 1). В Windows команда выглядит примерно так:
C:\Users\Al>python -m black -l 120 yourScript.py
Какую бы длину строки вы ни выбрали для своего проекта, для всех файлов
.py в проекте должно использоваться одинаковое значение.
Отключение настройки двойных кавычек для Black
Black автоматически изменяет все строковые литералы в вашем коде так, чтобы вместо одинарных кавычек они заключались в двойные кавычки, если только строка
82
Глава 3.Форматирование кода при помощи Black не содержит внутренние символы двойных кавычек; в этом случае используются одинарные кавычки. Допустим, файл yourScript.py содержит следующий фрагмент:
a = 'Hello' b = "Hello" c = 'Al\'s cat, Zophie.'
d = 'Zophie said, "Meow"' e = "Zophie said, \"Meow\"" f = '''Hello'''
После применения Black файл yourScript.py будет отформатирован следующим образом:
a = "Hello"
❶
b = "Hello"
c = "Al's cat, Zophie." d = 'Zophie said, "Meow"'
❷
e = 'Zophie said, "Meow"' f = """Hello"""
❸
В результате применения Black с настройками двойных кавычек код Python будет похож на код, написанный на других языках программирования, где строковые литералы часто заключаются в двойные кавычки. Обратите внимание: строки переменных a
, b
и c
используют двойные кавычки. Строка переменной d
сохраняет исходные одинарные кавычки, чтобы избежать исчезновения двойных кавычек в строке
❷
. Обратите внимание: Black также использует двойные кавычки для многострочных текстов Python, заключенных в тройные кавычки
❸
Но если вы хотите, чтобы ваши строковые литералы остались в том виде, в котором они были написаны, а тип используемых кавычек не изменялся, передайте Black ключ командной строки
-S
(обратите внимание: буква S в верхнем регистре). На- пример, при применении Black к исходному файлу yourScript.py в Windows будет получен следующий результат:
C:\Users\Al>python –m black -S yourScript.py
All done!
1 file left unchanged.
Также можно использовать ключи длины строки
-l и
-S
в одной команде:
C:\Users\Al>python –m black –l 120 -S yourScript.py
Предварительный просмотр изменений, вносимых Black
Хотя Black не переименовывает переменные и не изменяет работу программы, возможно, вам не понравятся стилевые изменения, предложенные Black. Если вы хотите оставить исходное форматирование, то либо используйте механизм контроля
Black: бескомпромиссная система форматирования кода
83
версий для исходного кода, либо создавайте резервные копии самостоятельно.
Также можно просмотреть изменения, которые внесет Black, без фактического из- менения файлов; для этого следует запустить Black с ключом командной строки
--diff
. В Windows это выглядит так:
C:\Users\Al>python -m black --diff yourScript.py
Эта команда выводит различия в формате diff
, который часто используется си- стемами контроля версий, но удобочитаем для людей. Например, если yourScript.py содержит строку weights=[42.0,3.1415,2.718]
, при выполнении с ключом
--diff будет выведен следующий результат:
C:\Users\Al\>python -m black --diff yourScript.py
--- yourScript.py 2020-12-07 02:04:23.141417 +0000
+++ yourScript.py 2020-12-07 02:08:13.893578 +0000
@@ -1 +1,2 @@
-weights=[42.0,3.1415,2.718]
+weights = [42.0, 3.1415, 2.718]
Знак «минус» означает, что Black удалит строку weights=[42.0,3.1415,2.718]
и за- менит ее строкой, которая выводится с префиксом «плюс»: weights
=
[42.0,
3.1415,
2.718]
. Учтите, что после того, как вы запустите Black для изменения файлов с ис- ходным кодом, отменить внесенные изменения уже не удастся. Необходимо либо создать резервные копии вашего исходного кода, либо воспользоваться системой контроля версий (такой как Git) перед запуском Black.
Отключение Black для отдельных частей кода
Каким бы замечательным ни был инструмент Black, возможно, вы не захотите, чтобы он форматировал некоторые части вашего кода. Например, я предпочитаю самостоятельно расставлять отступы в разделах, где я выравниваю несколько вза- имосвязанных команд присваивания, как в следующем примере:
# Константы для разных интервалов времени:
SECONDS_PER_MINUTE = 60
SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE
SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR
SECONDS_PER_WEEK = 7 * SECONDS_PER_DAY
Black удалит дополнительные пробелы перед оператором присваивания
=
, отчего они, по моему мнению, будут хуже читаться:
# Константы для разных интервалов времени:
SECONDS_PER_MINUTE = 60
SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE
SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR
SECONDS_PER_WEEK = 7 * SECONDS_PER_DAY
84
Глава 3.Форматирование кода при помощи Black
Добавив комментарии
#
fmt:
off и
#
fmt:
on
, можно запретить Black форматирование строк в этом фрагменте, а затем продолжить его:
# Константы для разных промежутков времени:
# fmt: off
SECONDS_PER_MINUTE = 60
SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE
SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR
SECONDS_PER_WEEK = 7 * SECONDS_PER_DAY
# fmt: on
Теперь запуск Black для этого файла не приведет к изменению отступов (и лю- бого другого форматирования) в коде между этими двумя комментариями.
Итоги
Хотя хорошее форматирование люди часто не замечают, плохое форматирование вызывает раздражение. Стиль — понятие субъективное, но у разработчиков обычно вырабатываются общие представления о том, что считать хорошим или плохим форматированием; при этом, конечно же, остается место для личных предпочтений.
Синтаксис Python достаточно гибок в том, что касается стиля. Если вы пишете код, который никто никогда не увидит, вы можете писать его так, как вам нравится.
Но разработкой ПО чаще всего занимаются в команде. Работаете ли вы с другими программистами над проектом или просто хотите попросить более опытных коллег оценить вашу работу, важно отформатировать код в соответствии с общепринятыми руководствами по стилю.
Форматирование кода в редакторе — монотонная работа, которую можно автома- тизировать таким инструментом, как Black. В этой главе рассмотрены некоторые правила, которым следует Black, для того чтобы сделать ваш код более удобочитае- мым: вертикальные и горизонтальные отступы, чтобы код не был слишком плотным и хорошо читался, и ограничение длины каждой строки. Black следит за соблюдением этих правил за вас, что предотвращает возможные стилевые разногласия с коллегами.
Однако стиль программирования не сводится к применению отступов и выбору между одинарными и двойными кавычками. Например, использование содержа- тельных имен переменных также является критическим фактором удобочитаемости кода. И хотя такие автоматизированные инструменты, как Black, могут принимать синтаксические решения (например, выбирать число отступов в коде), они не спо- собны принимать семантические решения — скажем, насколько удачно выбрано имя переменной. За это отвечаете вы. Об этом мы поговорим в следующей главе.
4
Выбор понятных имен
«В программировании есть только две сложные проблемы — выбор имен, аннулирование кэша и ошибки смещения на единицу» — эта классическая шутка, приписываемая Леону
Бамбрику (Leon Bambrick) и основанная на высказывании
Фила Карлтона (Phil Karlton), содержит зерно истины: трудно придумать хорошие имена (формально называемые идентифи-
каторами) для переменных, функций, классов и вообще чего угодно в програм- мировании. Компактные, содержательные имена важны для удобочитаемости вашей программы. Тем не менее это проще сказать, чем сделать. Если вы переез- жаете в новый дом, можно пометить все коробки надписью «Барахло» — надпись компактная, но не содержательная. Название книги по программированию «Как создавать собственные компьютерные игры на языке Python» — содержательное, но не компактное.
Если вы пишете не «одноразовый» код, который вы не собираетесь сопровождать после однократного запуска программы, вам стоит подумать над выбором хороших имен в вашей программе. Предположим, вы просто присвоили переменным имена a
, b
и c
, значит, вам в будущем придется потратить лишние усилия, чтобы запомнить, для чего предназначались эти переменные.
Выбор имен — субъективный выбор, который делаете именно вы. Автоматизи- рованные средства форматирования (такие как Black из главы 3) не способны решить, как должны называться ваши переменные. В этой главе я расскажу, как выбрать «хорошие» имена и избегать «плохих». Как обычно, мои рекомендации не высечены в камне; руководствуйтесь здравым смыслом, чтобы решить, когда стоит применять их в вашем коде.
86
Глава 4.Выбор понятных имен
МЕТАСИНТАКСИЧЕСКИЕ ПЕРЕМЕННЫЕ
Метасинтаксические переменные обычно используются в учебниках или фраг- ментах кода, когда необходимо обобщенное имя переменной. В Python в тех переменных, для которых имена несущественны, часто используют имена spam, eggs, bacon и ham. По этой причине я применяю их в примерах кода в книге, но не берите их для реальных программ. Имена происходят из скетча «Спам» группы Monty Python (https://en.wikipedia.org/wiki/Spam_(Monty_Python)).
Метасинтаксическим переменным также часто присваивают имена foo и bar.
Они происходят от сленгового сокращения FUBAR, которое использовали солдаты армии США во времена Второй Мировой войны, когда хотели со- общить, что ситуация «[уделана] до полной неузнаваемости».
Схемы регистра имен
Так как в идентификаторах Python различается регистр символов и они не могут содержать пробельные символы, программисты используют несколько схем в иден- тификаторах, состоящих из нескольких слов.
Змеиный регистр (
snake_case
) разделяет слова символом подчеркивания, который напоминает ползущую между словами змею. В этом случае все буквы записываются в нижнем регистре, а константы часто записываются в верхнем змеином регистре (
UPPER_SNAKE_CASE
).
Верблюжий регистр (
camelCase
) — слова записываются в нижнем регистре, но второе и следующие слова начинаются с заглавной. Эта схема в большин- стве случаев подразумевает, что первое слово начинается с буквы нижнего регистра. Буквы верхнего регистра напоминают верблюжьи горбы.
Схема Pascal (
PascalCase
) — названа так, потому что применяется в языке программирования Pascal; аналогична схеме верблюжьего регистра, но первое слово в ней тоже начинается с заглавной.
Выбор регистра относится к области форматирования кода, об этом я рассказывал в главе 3. На практике чаще всего встречаются змеиный и верблюжий регистры. Вы можете использовать любую схему, но в одном проекте — только одну, а не обе сразу.
Соглашения об именах PEP 8
В документе PEP 8 (глава 3) приведены некоторые правила формирования имен в Python.
Длина имен
87
Все буквы должны быть буквами ASCII — то есть латинскими буквами верхнего и нижнего регистров без диакритических знаков.
Имена модулей должны быть короткими и состоять только из букв нижнего регистра.
Имена классов необходимо записывать в схеме Pascal.
Имена констант следует записывать в верхнем змеином регистре.
Имена функций, методов и переменных записывают в нижнем змеином регистре.
Первый аргумент методов всегда должен называться self в нижнем регистре.
Первый аргумент методов классов всегда должен называться cls в нижнем регистре.
Приватные атрибуты классов всегда начинают с символа подчеркивания (
_
).
Публичные атрибуты классов никогда не начинают с символа подчеркива- ния (
_
).
При необходимости вы можете изменять или нарушать эти правила. Например, хотя английский язык доминирует в программировании, в идентификаторах можно использовать символы любых языков: команда コンピューター
=
'laptop'
является синтаксически действительным кодом Python. Как вы видите, мои предпочтения в области имен переменных противоречат PEP 8, потому что я использую верблю- жий регистр вместо змеиного. PEP 8 содержит напоминание о том, что программист не обязан неуклонно следовать PEP 8. Важнейший фактор удобочитаемости — не выбор схемы, а последовательность в применении этой схемы.
С разделом «Naming Conventions» документа PEP 8 можно ознакомиться по адресу
https://www.python.org/dev/peps/pep-0008/#naming-conventions.
Длина имен
Очевидно, имена не должны быть слишком короткими или слишком длинными.
Длинные имена переменных утомительно вводить, а короткие могут быть непонят- ными или дезинформирующими. Но так как код читают чаще, чем пишут, лучше все-таки задавать более длинные имена переменных. Рассмотрим примеры.
Слишком короткие имена
Самая распространенная ошибка при выборе имен — суперкороткие имена. Они зачастую кажутся вам понятными, когда вы впервые их записываете, но вы можете забыть их точный смысл через несколько дней или недель. Рассмотрим несколько разновидностей коротких имен.
88
Глава 4.Выбор понятных имен
Одно- или двухбуквенное имя (например, g
), вероятно, обозначает какое-то слово, начинающееся с этой буквы, но таких слов очень много. Сокращения и одно-двухбуквенные имена легко записать, но они плохо читаются. Это замечание относится и к следующему пункту.
Сокращенные имена вида mon
— могут означать monitor, month, monster и множество других слов.
Имя из одного слова — например, start
(начало) — может трактоваться по- разному: начало чего? При отсутствии уточнения другие люди вас вряд ли поймут.
Одно- и двухбуквенные имена, сокращения или однословные имена могут быть понятны вам, но всегда следует помнить, что другие программисты (или же вы сами через несколько недель) вряд ли поймут их смысл.
В отдельных случаях короткие имена переменных вполне допустимы. Например, имя i
часто используется с переменными циклов for
, перебирающих диапазоны чисел или индексов списка, а j
и k
(следующие за i
в алфавитном порядке) ис- пользуются с вложенными циклами:
>>>
1 2 3 4 5 6 7 8 9 10 ... 40
80
Глава 3.Форматирование кода при помощи Black
Я описал конкретные стилевые правила, используемые Black; полное руководство по стилю для Black вы найдете по адресу https://black.readthedocs.io/en/stable/
the_black_code_style.html.
Установка Black
Установите Black при помощи программы pip
, входящей в комплект поставки
Python. В Windows для этого следует открыть окно командной строки и ввести команду:
C:\Users\Al\>python -m pip install --user black
В macOS и Linux откройте окно терминала и введите команду python3
вместо python
(это следует делать во всех фрагментах кода в этой книге, где используется команда python
):
Als-MacBook-Pro: al$ python3 -m pip install --user black
Ключ
-m приказывает Python запустить модуль pip как приложение (некоторые модули Python имеют соответствующую настройку). Чтобы убедиться в том, что установка прошла успешно, выполните команду python
-m black
. На экране должно появиться сообщение «
No paths given.
Nothing to do
» вместо «
No module named black
».
Запуск Black из командной строки
Black можно запустить для любого файла Python из командной строки или окна терминала. Кроме того, IDE или редактор кода позволяет запустить Black в фоновом режиме. Инструкции о том, как обеспечить работу Black с Jupyter Notebook, Visual
Studio Code, PyCharm и другими редакторами, вы найдете на домашней странице
Black по адресу https://github.com/psf/black/.
Допустим, вы хотите отформатировать файл с именем yourScript.py автоматически.
В командной строке Windows выполните следующую команду (в macOS и Linux используйте команду python3
вместо python
):
C:\Users\Al>python -m black yourScript.py
После выполнения этой команды содержимое yourScript.py будет отформатировано в соответствии с руководством по стилю Black.
Переменная среды
PATH
может быть уже настроена для прямого запуска Black.
В этом случае для форматирования yourScript.py достаточно ввести следующую команду:
C:\Users\Al>black yourScript.py
Black: бескомпромиссная система форматирования кода
81
Чтобы выполнить Black для каждого файла
.py в папке, укажите в команде папку вместо отдельного файла. Следующий пример Windows форматирует все файлы в папке
C:\yourPythonFiles
, включая ее вложенные папки:
C:\Users\Al>python -m black C:\yourPythonFiles
Передача папки пригодится в том случае, если ваш проект содержит несколько файлов Python и вы не хотите вводить отдельную команду для каждого файла.
Хотя Black довольно строго относится к форматированию кода, в следующих трех подразделах описаны некоторые параметры, которые вы можете настроить. Что- бы просмотреть полный набор ключей Black, выполните команду python
-m black
--help
Регулировка длины строки Black
Стандартная строка кода Python состоит из 80 символов. История 80-символьных строк уходит корнями в 1920-е годы, когда компания IBM представила перфокар- ты на 80 столбцов и 12 строк; 80-символьный стандарт стал использоваться для принтеров, мониторов и окон командной строки, появившихся через несколько десятилетий.
Но в XXI веке экраны с высоким разрешением позволяют выводить текст длиной более 80 символов. С большей длиной строки вам не придется выполнять верти- кальную прокрутку, чтобы просмотреть файл. С другой стороны, короткие строки не перегружены, а вы можете сравнить два исходных файла, разместив их на экране рядом друг с другом, без горизонтальной прокрутки.
Black по умолчанию использует строку длиной 88 символов. Выбор объясняется не очень убедительно: это на 10% больше стандартной 80-символьной строки.
Лично я предпочитаю 120 символов. Чтобы приказать Black форматировать код с 120-символьной (например) строкой, используйте ключ командной строки
-l
120
(буква l в нижнем регистре, не цифра 1). В Windows команда выглядит примерно так:
C:\Users\Al>python -m black -l 120 yourScript.py
Какую бы длину строки вы ни выбрали для своего проекта, для всех файлов
.py в проекте должно использоваться одинаковое значение.
Отключение настройки двойных кавычек для Black
Black автоматически изменяет все строковые литералы в вашем коде так, чтобы вместо одинарных кавычек они заключались в двойные кавычки, если только строка
82
Глава 3.Форматирование кода при помощи Black не содержит внутренние символы двойных кавычек; в этом случае используются одинарные кавычки. Допустим, файл yourScript.py содержит следующий фрагмент:
a = 'Hello' b = "Hello" c = 'Al\'s cat, Zophie.'
d = 'Zophie said, "Meow"' e = "Zophie said, \"Meow\"" f = '''Hello'''
После применения Black файл yourScript.py будет отформатирован следующим образом:
a = "Hello"
❶
b = "Hello"
c = "Al's cat, Zophie." d = 'Zophie said, "Meow"'
❷
e = 'Zophie said, "Meow"' f = """Hello"""
❸
В результате применения Black с настройками двойных кавычек код Python будет похож на код, написанный на других языках программирования, где строковые литералы часто заключаются в двойные кавычки. Обратите внимание: строки переменных a
, b
и c
используют двойные кавычки. Строка переменной d
сохраняет исходные одинарные кавычки, чтобы избежать исчезновения двойных кавычек в строке
❷
. Обратите внимание: Black также использует двойные кавычки для многострочных текстов Python, заключенных в тройные кавычки
❸
Но если вы хотите, чтобы ваши строковые литералы остались в том виде, в котором они были написаны, а тип используемых кавычек не изменялся, передайте Black ключ командной строки
-S
(обратите внимание: буква S в верхнем регистре). На- пример, при применении Black к исходному файлу yourScript.py в Windows будет получен следующий результат:
C:\Users\Al>python –m black -S yourScript.py
All done!
1 file left unchanged.
Также можно использовать ключи длины строки
-l и
-S
в одной команде:
C:\Users\Al>python –m black –l 120 -S yourScript.py
Предварительный просмотр изменений, вносимых Black
Хотя Black не переименовывает переменные и не изменяет работу программы, возможно, вам не понравятся стилевые изменения, предложенные Black. Если вы хотите оставить исходное форматирование, то либо используйте механизм контроля
Black: бескомпромиссная система форматирования кода
83
версий для исходного кода, либо создавайте резервные копии самостоятельно.
Также можно просмотреть изменения, которые внесет Black, без фактического из- менения файлов; для этого следует запустить Black с ключом командной строки
--diff
. В Windows это выглядит так:
C:\Users\Al>python -m black --diff yourScript.py
Эта команда выводит различия в формате diff
, который часто используется си- стемами контроля версий, но удобочитаем для людей. Например, если yourScript.py содержит строку weights=[42.0,3.1415,2.718]
, при выполнении с ключом
--diff будет выведен следующий результат:
C:\Users\Al\>python -m black --diff yourScript.py
--- yourScript.py 2020-12-07 02:04:23.141417 +0000
+++ yourScript.py 2020-12-07 02:08:13.893578 +0000
@@ -1 +1,2 @@
-weights=[42.0,3.1415,2.718]
+weights = [42.0, 3.1415, 2.718]
Знак «минус» означает, что Black удалит строку weights=[42.0,3.1415,2.718]
и за- менит ее строкой, которая выводится с префиксом «плюс»: weights
=
[42.0,
3.1415,
2.718]
. Учтите, что после того, как вы запустите Black для изменения файлов с ис- ходным кодом, отменить внесенные изменения уже не удастся. Необходимо либо создать резервные копии вашего исходного кода, либо воспользоваться системой контроля версий (такой как Git) перед запуском Black.
Отключение Black для отдельных частей кода
Каким бы замечательным ни был инструмент Black, возможно, вы не захотите, чтобы он форматировал некоторые части вашего кода. Например, я предпочитаю самостоятельно расставлять отступы в разделах, где я выравниваю несколько вза- имосвязанных команд присваивания, как в следующем примере:
# Константы для разных интервалов времени:
SECONDS_PER_MINUTE = 60
SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE
SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR
SECONDS_PER_WEEK = 7 * SECONDS_PER_DAY
Black удалит дополнительные пробелы перед оператором присваивания
=
, отчего они, по моему мнению, будут хуже читаться:
# Константы для разных интервалов времени:
SECONDS_PER_MINUTE = 60
SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE
SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR
SECONDS_PER_WEEK = 7 * SECONDS_PER_DAY
84
Глава 3.Форматирование кода при помощи Black
Добавив комментарии
#
fmt:
off и
#
fmt:
on
, можно запретить Black форматирование строк в этом фрагменте, а затем продолжить его:
# Константы для разных промежутков времени:
# fmt: off
SECONDS_PER_MINUTE = 60
SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE
SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR
SECONDS_PER_WEEK = 7 * SECONDS_PER_DAY
# fmt: on
Теперь запуск Black для этого файла не приведет к изменению отступов (и лю- бого другого форматирования) в коде между этими двумя комментариями.
Итоги
Хотя хорошее форматирование люди часто не замечают, плохое форматирование вызывает раздражение. Стиль — понятие субъективное, но у разработчиков обычно вырабатываются общие представления о том, что считать хорошим или плохим форматированием; при этом, конечно же, остается место для личных предпочтений.
Синтаксис Python достаточно гибок в том, что касается стиля. Если вы пишете код, который никто никогда не увидит, вы можете писать его так, как вам нравится.
Но разработкой ПО чаще всего занимаются в команде. Работаете ли вы с другими программистами над проектом или просто хотите попросить более опытных коллег оценить вашу работу, важно отформатировать код в соответствии с общепринятыми руководствами по стилю.
Форматирование кода в редакторе — монотонная работа, которую можно автома- тизировать таким инструментом, как Black. В этой главе рассмотрены некоторые правила, которым следует Black, для того чтобы сделать ваш код более удобочитае- мым: вертикальные и горизонтальные отступы, чтобы код не был слишком плотным и хорошо читался, и ограничение длины каждой строки. Black следит за соблюдением этих правил за вас, что предотвращает возможные стилевые разногласия с коллегами.
Однако стиль программирования не сводится к применению отступов и выбору между одинарными и двойными кавычками. Например, использование содержа- тельных имен переменных также является критическим фактором удобочитаемости кода. И хотя такие автоматизированные инструменты, как Black, могут принимать синтаксические решения (например, выбирать число отступов в коде), они не спо- собны принимать семантические решения — скажем, насколько удачно выбрано имя переменной. За это отвечаете вы. Об этом мы поговорим в следующей главе.
4
Выбор понятных имен
«В программировании есть только две сложные проблемы — выбор имен, аннулирование кэша и ошибки смещения на единицу» — эта классическая шутка, приписываемая Леону
Бамбрику (Leon Bambrick) и основанная на высказывании
Фила Карлтона (Phil Karlton), содержит зерно истины: трудно придумать хорошие имена (формально называемые идентифи-
каторами) для переменных, функций, классов и вообще чего угодно в програм- мировании. Компактные, содержательные имена важны для удобочитаемости вашей программы. Тем не менее это проще сказать, чем сделать. Если вы переез- жаете в новый дом, можно пометить все коробки надписью «Барахло» — надпись компактная, но не содержательная. Название книги по программированию «Как создавать собственные компьютерные игры на языке Python» — содержательное, но не компактное.
Если вы пишете не «одноразовый» код, который вы не собираетесь сопровождать после однократного запуска программы, вам стоит подумать над выбором хороших имен в вашей программе. Предположим, вы просто присвоили переменным имена a
, b
и c
, значит, вам в будущем придется потратить лишние усилия, чтобы запомнить, для чего предназначались эти переменные.
Выбор имен — субъективный выбор, который делаете именно вы. Автоматизи- рованные средства форматирования (такие как Black из главы 3) не способны решить, как должны называться ваши переменные. В этой главе я расскажу, как выбрать «хорошие» имена и избегать «плохих». Как обычно, мои рекомендации не высечены в камне; руководствуйтесь здравым смыслом, чтобы решить, когда стоит применять их в вашем коде.
86
Глава 4.Выбор понятных имен
МЕТАСИНТАКСИЧЕСКИЕ ПЕРЕМЕННЫЕ
Метасинтаксические переменные обычно используются в учебниках или фраг- ментах кода, когда необходимо обобщенное имя переменной. В Python в тех переменных, для которых имена несущественны, часто используют имена spam, eggs, bacon и ham. По этой причине я применяю их в примерах кода в книге, но не берите их для реальных программ. Имена происходят из скетча «Спам» группы Monty Python (https://en.wikipedia.org/wiki/Spam_(Monty_Python)).
Метасинтаксическим переменным также часто присваивают имена foo и bar.
Они происходят от сленгового сокращения FUBAR, которое использовали солдаты армии США во времена Второй Мировой войны, когда хотели со- общить, что ситуация «[уделана] до полной неузнаваемости».
Схемы регистра имен
Так как в идентификаторах Python различается регистр символов и они не могут содержать пробельные символы, программисты используют несколько схем в иден- тификаторах, состоящих из нескольких слов.
Змеиный регистр (
snake_case
) разделяет слова символом подчеркивания, который напоминает ползущую между словами змею. В этом случае все буквы записываются в нижнем регистре, а константы часто записываются в верхнем змеином регистре (
UPPER_SNAKE_CASE
).
Верблюжий регистр (
camelCase
) — слова записываются в нижнем регистре, но второе и следующие слова начинаются с заглавной. Эта схема в большин- стве случаев подразумевает, что первое слово начинается с буквы нижнего регистра. Буквы верхнего регистра напоминают верблюжьи горбы.
Схема Pascal (
PascalCase
) — названа так, потому что применяется в языке программирования Pascal; аналогична схеме верблюжьего регистра, но первое слово в ней тоже начинается с заглавной.
Выбор регистра относится к области форматирования кода, об этом я рассказывал в главе 3. На практике чаще всего встречаются змеиный и верблюжий регистры. Вы можете использовать любую схему, но в одном проекте — только одну, а не обе сразу.
Соглашения об именах PEP 8
В документе PEP 8 (глава 3) приведены некоторые правила формирования имен в Python.
Длина имен
87
Все буквы должны быть буквами ASCII — то есть латинскими буквами верхнего и нижнего регистров без диакритических знаков.
Имена модулей должны быть короткими и состоять только из букв нижнего регистра.
Имена классов необходимо записывать в схеме Pascal.
Имена констант следует записывать в верхнем змеином регистре.
Имена функций, методов и переменных записывают в нижнем змеином регистре.
Первый аргумент методов всегда должен называться self в нижнем регистре.
Первый аргумент методов классов всегда должен называться cls в нижнем регистре.
Приватные атрибуты классов всегда начинают с символа подчеркивания (
_
).
Публичные атрибуты классов никогда не начинают с символа подчеркива- ния (
_
).
При необходимости вы можете изменять или нарушать эти правила. Например, хотя английский язык доминирует в программировании, в идентификаторах можно использовать символы любых языков: команда コンピューター
=
'laptop'
является синтаксически действительным кодом Python. Как вы видите, мои предпочтения в области имен переменных противоречат PEP 8, потому что я использую верблю- жий регистр вместо змеиного. PEP 8 содержит напоминание о том, что программист не обязан неуклонно следовать PEP 8. Важнейший фактор удобочитаемости — не выбор схемы, а последовательность в применении этой схемы.
С разделом «Naming Conventions» документа PEP 8 можно ознакомиться по адресу
https://www.python.org/dev/peps/pep-0008/#naming-conventions.
Длина имен
Очевидно, имена не должны быть слишком короткими или слишком длинными.
Длинные имена переменных утомительно вводить, а короткие могут быть непонят- ными или дезинформирующими. Но так как код читают чаще, чем пишут, лучше все-таки задавать более длинные имена переменных. Рассмотрим примеры.
Слишком короткие имена
Самая распространенная ошибка при выборе имен — суперкороткие имена. Они зачастую кажутся вам понятными, когда вы впервые их записываете, но вы можете забыть их точный смысл через несколько дней или недель. Рассмотрим несколько разновидностей коротких имен.
88
Глава 4.Выбор понятных имен
Одно- или двухбуквенное имя (например, g
), вероятно, обозначает какое-то слово, начинающееся с этой буквы, но таких слов очень много. Сокращения и одно-двухбуквенные имена легко записать, но они плохо читаются. Это замечание относится и к следующему пункту.
Сокращенные имена вида mon
— могут означать monitor, month, monster и множество других слов.
Имя из одного слова — например, start
(начало) — может трактоваться по- разному: начало чего? При отсутствии уточнения другие люди вас вряд ли поймут.
Одно- и двухбуквенные имена, сокращения или однословные имена могут быть понятны вам, но всегда следует помнить, что другие программисты (или же вы сами через несколько недель) вряд ли поймут их смысл.
В отдельных случаях короткие имена переменных вполне допустимы. Например, имя i
часто используется с переменными циклов for
, перебирающих диапазоны чисел или индексов списка, а j
и k
(следующие за i
в алфавитном порядке) ис- пользуются с вложенными циклами:
>>>
1 2 3 4 5 6 7 8 9 10 ... 40