ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 03.12.2023
Просмотров: 364
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
218
Глава 11.Комментарии, doc-строки и аннотации типов
Стиль комментариев
Примеры комментариев, отвечающих правилам хорошего стиля:
# Комментарий, относящийся к следующему коду:
❶
someCode()
# Более длинный комментарий, который занимает несколько строк
❷
# из нескольких последовательных однострочных комментариев.
#
❸
# Такие комментарии называются блоковыми.
if someCondition:
# Комментарий о другом коде:
❹
someOtherCode() # Встроенный комментарий.
❺
Как правило, комментарии лучше размещать в отдельной строке, а не в конце строки с кодом. В большинстве случаев лучше использовать полноценные предложения с соответствующим регистром символов и знаками препинания, а не короткие фразы или отдельные слова
❶
. При этом комментарии должны подчиняться тем же ограничениям длины строки, что и исходный код. Комментарии, занимающие несколько строк
❷
, могут состоять из нескольких последовательных однострочных комментариев (такие комментарии называются блоковыми). Абзацы в коммен- тариях разделяются пустым однострочным комментарием
❸
. Уровень отступа комментария должен соответствовать уровню отступов в комментируемом коде
❹
Комментарии, следующие за строкой кода, называются встроенными (inline)
❺
, и код отделяется от комментария минимум двумя пробелами.
В однострочных комментариях после знака
#
ставят пробел:
#Комментарий не должен начинаться сразу же после знака #.
Комментарии могут включать ссылки на URL с сопутствующей информацией, но ссылки не должны заменять комментарии, потому что связанный с ними контент может исчезнуть из интернета в любой момент:
# Подробное объяснение некоторого аспекта кода с дополнительной
# информацией по URL. Подробнее см. https://example.com
Все эти соглашения являются делом стиля, а не контента, но они вносят свой вклад в удобочитаемость комментариев. Чем лучше читаются комментарии, тем с большей вероятностью программисты обратят на них внимание, — а комментарии приносят пользу только в том случае, если программисты их читают.
1 ... 18 19 20 21 22 23 24 25 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
Встроенные комментарии размещаются в конце строки:
while True: # Пока игрок не введет допустимый ход.
Комментарии
219
Встроенные комментарии коротки, потому что они должны укладываться в огра- ничения длины строки, указанные в руководстве по стилю. Это означает, что они могут оказаться слишком короткими, чтобы содержать достаточную информацию.
Если вы решите использовать встроенные комментарии, убедитесь в том, что ком- ментарий описывает только непосредственно предшествующую ему строку кода.
Если вашему встроенному комментарию требуется больше места или он описывает другие строки кода, разместите его в отдельной строке.
Встроенные комментарии чаще всего применяют — и это весьма уместно — для по- яснения смысла переменных или другой информации, относящейся к переменным.
Такие встроенные комментарии записываются в команде присваивания, которая создает переменную:
TOTAL_DISKS = 5 # Чем больше дисков, тем сложнее головоломка.
Другое типичное применение встроенных комментариев — добавление информации о значениях переменных при их создании:
month = 2 # Месяцы пронумерованы от 0 (январь) до 11 (декабрь).
catWeight = 4.9 # Вес в килограммах.
website = 'inventwithpython.com' # Префикс "https://" не включается.
Во встроенных комментариях не следует указывать тип данных переменной, потому что он должен быть очевиден из команды присваивания; исключение составляет такая разновидность комментариев, как аннотации типов (см. подраздел «Обратное портирование аннотаций типов» далее в этой главе, с. 232).
Пояснительные комментарии
Как правило, комментарии должны сообщать, почему код был написан именно так, а не иначе, что он делает или как он это делает. Даже при использовании правиль- ного стиля кода и полезных соглашений об именах, о которых я рассказывал в гла- вах 3 и 4, реальный код не способен объяснить, какие задачи ставил программист.
Если вы сами написали код, то через несколько недель можете забыть какие-то подробности. Поэтому лучше сегодня дать содержательные комментарии, чтобы завтра вам не пришлось проклинать вас вчерашнего. Например, ниже приведен бесполезный комментарий, который объясняет, что делает код. Вместо того чтобы пояснить задачу кода, он констатирует очевидное:
>>> currentWeekWages *= 1.5 # Заработок за текущую неделю умножается на 1.5
Такой комментарий хуже бесполезного. Из кода и так очевидно, что переменная currentWeekWages умножается на
1.5
, и если полностью убрать комментарий, это только упростит ваш код. Следующий комментарий гораздо лучше:
>>> currentWeekWages *= 1.5 # Включить в расчет полуторную ставку.
220
Глава 11.Комментарии, doc-строки и аннотации типов
Этот комментарий объясняет смысл строки кода, а не пересказывает, как тот ра- ботает. Он предоставляет информацию, которую даже хорошо написанный код передать не сможет.
Сводные комментарии
Практическая польза комментариев не ограничивается пояснением намерений про- граммиста. Краткие комментарии, резюмирующие работу нескольких строк кода, позволяют читателю бегло просмотреть исходник и получить общее представление о том, что он делает. Программисты часто вставляют пустые строки, чтобы отделить
«абзацы» кода друг от друга. Сводные комментарии обычно занимают одну строку в начале таких абзацев. В отличие от однострочных комментариев, поясняющих отдельные строки кода, сводные комментарии на более высоком уровне абстракции описывают, что делает код.
Например, из следующих четырех строк кода можно понять, что они присваивают переменной playerTurn значение, обозначающее другого игрока. Но короткий одно- строчный комментарий избавит читателя от необходимости читать и обдумывать код, чтобы понять смысл происходящего:
# Ход передается другому игроку:
if playerTurn == PLAYER_X:
playerTurn = PLAYER_O
elif playerTurn == PLAYER_O:
playerTurn = PLAYER_X
Если вы включите эти сводные комментарии в свою программу, это значительно упростит ее чтение. Далее программист сможет внимательнее проанализировать те места, которые вызывают у него особый интерес. Сводные комментарии также препятствуют формированию ошибочных представлений о том, что делает код.
Краткий сводный комментарий позволяет разработчику удостовериться, что он правильно понял, как работает код.
Комментарии «полученный опыт»
Когда я работал в компании, занимающейся разработкой программного обеспече- ния, однажды мне предложили адаптировать библиотеку построения графиков — требовалось, чтобы она в реальном времени обновляла миллионы точек данных на диаграмме. Используемая библиотека могла либо обновлять графики в реальном времени, либо поддерживать графики с миллионами точек данных, но не то и дру- гое одновременно. Я думал, что справлюсь с этой задачей за несколько дней. Через три недели я все еще был убежден, что до окончания работы рукой подать. Каждый день мне казалось, что решение совсем рядом, и на пятую неделю у меня появился рабочий прототип.
Комментарии
221
За это время я много узнал о том, как работает библиотека, каковы ее возможности и ограничения. Поэтому я потратил несколько часов на то, чтобы оформить мои знания в комментарий длиной в страницу, который я включил в исходный код.
Я был убежден, что каждый, кому потребуется внести изменения в работу про- граммы, столкнется с теми же (простыми на первый взгляд) проблемами, что и я, а написанная мной документация сэкономит им целые недели работы.
Такие комментарии могут занимать несколько абзацев, из-за чего они кажутся неуместными в файлах с исходным кодом. Но содержащаяся в них информация бесценна для любого специалиста, который будет заниматься сопровождением программы. Не бойтесь включать в свой код длинные, подробные комментарии, которые объясняют, как он работает. Другие программисты могут не знать тонкости вашей реализации кода, они могут понять их неправильно или упустить их из виду.
Если разработчика комментарии не интересуют, он с легкостью их пропустит, зато те, кому они нужны, будут благодарны.
Как и в предыдущих случаях, этот вид комментариев не должен заменять докумен- тацию модуля или функции (для которой создаются doc-строки). Комментарии типа
«полученный опыт» — не учебник и не сборник рецептов для пользователей програм- мы. Они предназначены для разработчиков, читающих исходный код. Так как мой комментарий относился к библиотеке с открытым кодом и мог пригодиться другим, я опубликовал его в ответе на общедоступном сайте https://stackoverflow.org, где он оказался доступен другим пользователям, оказавшимся в аналогичной ситуации.
Комментарии об авторских правах и интеллектуальной собственности
Некоторые компании-разработчики или проекты с открытым кодом используют политику включения сведений об авторских правах и интеллектуальной собствен- ности, а также текстов лицензий в начало каждого файла с исходным кодом. Такие аннотации должны содержать всего несколько строк и выглядеть примерно так:
"""Cat Herder 3.0 Copyright (C) 2021 Al Sweigart. All rights reserved.
See license.txt for the full text."""
Если возможно, включите ссылку на внешний документ или веб-сайт с полным текстом лицензии (вместо того, чтобы включать всю длинную лицензию в начало каждого файла с исходным кодом). Прокручивать несколько лишних экранов текста каждый раз, когда вы открываете файл с исходным кодом, утомительно, а публика- ция текста полной лицензии не обеспечивает дополнительной юридической защиты.
Профессиональные комментарии
На моей первой работе в качестве программиста старший коллега, которого я очень уважал, отвел меня в сторону и объяснил, что поскольку мы иногда
222
Глава 11.Комментарии, doc-строки и аннотации типов предоставляем исходный код наших продуктов клиентам, очень важно выдер- живать профессиональный тон в комментариях. Как выяснилось, я написал
«Какого черта?» в одном из комментариев, относящихся к особенно противной части кода. Я устыдился, немедленно извинился и отредактировал текст. С этого момента я пишу в комментариях (даже в персональных проектах) только про- фессиональные замечания.
Возможно, вам захочется высказать свое раздражение или проявить остроумие в комментариях программы, но делать так не стоит. Вы не знаете, кто будет читать ваш код в будущем, а тональность текста легко интерпретируется неверно. Как я объяснял в разделе «Избегайте шуток, каламбуров и культурных отсылок», с. 91, лучше всего писать комментарии прямолинейно, четко и без юмора.
Кодовые метки и комментарии TODO
Программисты иногда оставляют короткие комментарии, напоминающие им о работе, которую еще предстоит сделать. Обычно их оформляют в виде кодовых
меток — комментариев, которые предваряет метка, записанная в верхнем регистре
(например,
TODO
). В идеале для памяток лучше использовать средства управления проектами, а не зарывать их в исходном коде. Но в небольших персональных про- ектах, в которых такие инструменты не используются, встречающиеся время от времени метки
TODO
могут стать полезным напоминанием. Пример:
_chargeIonFluxStream() # TODO: Выяснить, почему каждый вторник происходит сбой.
Для таких напоминаний часто используются следующие метки:
TODO
— общее напоминание о работе, которую необходимо выполнить;
FIXME
— эта часть кода работает не полностью;
HACK
— эта часть кода работает (возможно, по минимуму), но ее можно улучшить;
XXX
— общее предупреждение, часто весьма серьезное.
За метками, записанными в верхнем регистре, следует давать более конкретные описания задачи или проблемы. Позднее вы сможете провести поиск меток в ис- ходном коде и найти фрагмент, который необходимо доработать.
С другой стороны, у таких напоминаний есть и недостаток: о них легко забыть, если только вы не читаете ту часть кода, где они находятся. Кодовые метки не заменяют формальной системы отслеживания ошибок или программ отправки отчетов об ошибках. Если вы используете кодовые метки в своей программе, я рекомендую предельно упростить их: используйте только
TODO
и откажитесь от остальных.
Doc-строки
223
Магические комментарии и кодировка исходных файлов
Возможно, вам встречались исходные файлы
.py
, в начале которых находились строки следующего вида:
#!/usr/bin/env python3
❶
# -*- coding: utf-8 -*-
❷
Магические комментарии в начале файла предоставляют информацию об интерпре- таторе или кодировке. Строка
❶
(о которой я упоминал в главе 2) сообщает вашей операционной системе, какой интерпретатор следует использовать для выполнения инструкций в файле.
Второй магический комментарий в строке
❷
определяет кодировку. В данном случае строка определяет, что для этого исходного файла должна использоваться кодировка UTF-8. Включать эту строку почти всегда не обязательно, потому что большинство редакторов и IDE уже сохраняет файлы с исходным кодом в кодировке
UTF-8, а все версии Python, начиная с Python 3.0, определяют UTF-8 как кодировку по умолчанию. Файлы в кодировке UTF-8 могут содержать любые символы, так что ничто не мешает вам включить в исходный файл
.py английские, китайские или арабские символы.
Если вам потребуется информация о Юникоде и кодировке строк, я рекомендую публикацию в блоге Неда Бэтчелдера (Ned Batchelder) «Pragmatic Unicode» по адресу https://nedbatchelder.com/text/unipain.html.
Doc-строки
Doc-строки представляют собой многострочные комментарии, расположенные либо в начале файла
.py с исходным кодом модуля, либо непосредственно после коман- ды class или def
. Они содержат документацию об определяемом модуле, классе, функции или методе. Средства автоматизированного генерирования документации используют их для генерирования внешних файлов с документацией — например, справочных файлов или веб-страниц.
Doc-строки должны быть оформлены в виде многострочных комментариев в трой- ных кавычках (вместо однострочных комментариев, начинающихся с решетки
#
).
Doc-строки всегда используют утроенные двойные кавычки вместо утроенных одинарных кавычек. Например, ниже приведен фрагмент файла sessions.py из по- пулярного модуля requests
:
# -*- coding: utf-8 -*-
❶
"""
❷
requests.session
224
Глава 11.Комментарии, doc-строки и аннотации типов
This module provides a Session object to manage and persist settings across requests (cookies, auth, proxies)
"""
import os import sys
--snip—
class Session(SessionRedirectMixin):
"""A Requests session.
❸
Provides cookie persistence, connection-pooling, and configuration.
Basic Usage::
>>> import requests
>>> s = requests.Session()
>>> s.get('https://httpbin.org/get')
--snip--
def get(self, url, **kwargs):
r"""Sends a GET request. Returns :class:`Response` object.
❹
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
--snip--
Файл sessions.py содержит doc-строки для модуля
❷
, класса
Session
❸
и метода get()
класса
Session
❹
. Обратите внимание: хотя doc-строка модуля должна быть первой строкой в модуле, она располагается после любых специальных комментариев — в частности, определения кодировки
❶
Позднее вы можете прочитать doc-строки модуля, класса, функции или метода, проверяя атрибут
__doc__
соответствующего объекта. Так, в следующем примере проверяются doc-строки для получения дополнительной информации о модуле sessions, классе
Session и методе get()
:
>>> from requests import sessions
>>> sessions.__doc__
'\nrequests.session\n\n\nThis module provides a Session object to manage and persist settings across\nrequests (cookies, auth, proxies).\n'
>>> sessions.Session.__doc__
"A Requests session.\n\n Provides cookie persistence, connection-pooling, and configuration.\n\n Basic Usage::\n\n >>> import requests\n
--snip--
>>> sessions.Session.get.__doc__
'Sends a GET request. Returns :class:`Response` object.\n\n :param url:
URL for the new :class:`Request` object.\n :param \\*\\*kwargs:
--snip--
Doc-строки
225
Средства автоматизированного документирования могут пользоваться doc- строками для предоставления информации, соответствующей контексту. Одно из таких средств — встроенная функция Python help()
— выводит doc-строку пере- данного ей объекта в более удобочитаемом формате, чем у необработанной строки
__doc__
. Данная возможность может оказаться полезной при экспериментах с ин- терактивной оболочкой, потому что вы можете немедленно получить информацию о любых модулях, классах и функциях, которые вы пытаетесь использовать:
>>> from requests import sessions
>>> help(sessions)
Help on module requests.sessions in requests:
NAME
requests.sessions
DESCRIPTION
requests.session
This module provides a Session object to manage and persist settings
-- More --
Если doc-строка слишком велика, чтобы поместиться на экране, Python выводит подсказку
--
More
-- в нижней части окна. Нажмите ENTER, чтобы прокрутить текст к следующей строке, пробел для вывода следующей страницы или Q для прекращения просмотра doc-строки.
В общем случае doc-строка должна содержать одну строку текста с обобщающим описанием модуля, класса или функции, за которым следует пустая строка и более подробная информация. Для функций и методов она может включать информацию об их параметрах, возвращаемом значении и побочных эффектах. Doc-строки пи- шутся для других программистов, а не для пользователей программы, поэтому они должны содержать техническую информацию, а не обучающие советы.
У doc-строк также есть второе ключевое преимущество: они интегрируют доку- ментацию в исходный код. Когда документация пишется отдельно от кода, о ней часто вообще забывают. С другой стороны, когда doc-строки размещены в начале модулей, классов и функций, информацию легко просматривать и обновлять.
Возможно, вы не сможете сразу писать doc-строки, если работа над кодом, ко- торый вы хотите описывать, еще не завершена. В таком случае включите в doc- строку комментарий
TODO
с напоминанием. Например, следующая вымышленная функция reverseCatPolarity()
содержит плохую doc-строку, которая утверждает очевидное:
def reverseCatPolarity(catId, catQuantumPhase, catVoltage):
"""Reverses the polarity of a cat.
226
Глава 11.Комментарии, doc-строки и аннотации типов
TODO Finish this docstring."""
--snip--
( """Меняет полярность у кота.
TODO: Закончить эту doc-строку)
Так как каждый класс, функция и метод должны содержать doc-строку, может по- явиться искушение написать минимальную документацию и двигаться дальше. Без комментария
TODO
слишком легко забыть о том, что doc-строку следует переписать.
PEP 257 содержит дополнительную документацию о doc-строках по адресу https://
www.python.org/dev/peps/pep-0257/.
Аннотации типов
Во многих языках программирования используется статическая типизация; это означает, что программист должен объявить типы данных всех переменных, пара- метров и возвращаемых значений в исходном коде. Такая возможность позволяет интерпретатору или компилятору проверить правильность применения всех объ- ектов до запуска программы. В Python используется динамическая типизация: переменные, параметры и возвращаемые значения могут иметь любой тип данных и даже менять типы данных во время выполнения программы. На динамических языках обычно проще программировать, потому что они требуют меньше формаль- ных определений, но зато в них отсутствуют средства предотвращения ошибок, присущие статическим языкам. Когда вы пишете строку кода Python — например, round('forty two')
, вы можете не понять, что строка передается функции, полу- чающей только аргументы int и float
, пока программа не будет запущена и не про- изойдет ошибка. Языки со статической типизацией выдают ранние предупреждения при присваивании значения или передаче аргумента неправильного типа.
Аннотации типов в Python предоставляют необязательные средства статической типизации. В следующем примере аннотации типов выделены жирным шрифтом:
def describeNumber(number
1 ... 19 20 21 22 23 24 25 26 ... 40
: int) -> str:
if number % 2 == 1:
return 'An odd number. '
elif number == 42:
return 'The answer. '
else:
return 'Yes, that is a number. '
myLuckyNumber: int = 42
print(describeNumber(myLuckyNumber))
Как видите, для параметров или переменных аннотация типа использует двоеточие для отделения имени от типа, тогда как для возвращаемых значений закрывающая круглая скобка команды def отделяется от типа стрелкой (
->
). Аннотации типов
Аннотации типов
227
функции describeNumber()
показывают, что функция получает целое число в па- раметре number и возвращает строковое значение.
Если вы используете аннотации типов, вам не нужно применять их к каждому зна- чению данных в программе. Вместо этого можно воспользоваться методом посте-
пенной типизации, сочетающим гибкость динамической типизации с безо пасностью статической типизации: аннотации типов включаются только для некоторых пере- менных, параметров и возвращаемых значений. Но чем больше аннотаций типов появляется в вашей программе, тем больше информации получат средства стати- ческого анализа кода для выявления потенциальных ошибок в вашей программе.
Обратите внимание: в этом примере имена заданных типов совпадают с именами функций-конструкторов int()
и str()
. В Python термины «класс», «тип» и «тип данных» имеют одинаковый смысл. Для любых экземпляров, созданных на основе классов, имя класса используется как его тип:
import datetime noon: datetime.time = datetime.time(12, 0, 0)
❶
class CatTail:
def __init__(self, length: int, color: str) -> None:
self.length = length self.color = color zophieTail: CatTail = CatTail(29, 'grey')
❷
Переменная noon снабжена аннотацией типа datetime.time
❶
, потому что это объект time
(определенный в модуле datetime
). Аналогичным образом объект zophieTail снабжен аннотацией типа
CatTail
❷
, потому что это объект класса
CatTail
, создан- ного командой class
. Аннотации типов автоматически распространяются на все субклассы заданного типа. Например, переменной с аннотацией типа dict можно присвоить не только любое значение словаря, но и любое из значений collections.
OrderedDict и collections.defaultdict
, потому что эти классы являются субклас- сами dict
. О субклассах мы более подробно поговорим в главе 16.
Средствам статической проверки типов не обязательно нужны аннотации типов для переменных. Дело в том, что средства статической проверки типов выполняют автоматическое определение типа на основании первой команды присваивания переменной. Например, по строке spam
=
42
система проверки типов может автома- тически определить, что переменная spam должна иметь аннотацию типа int
. Тем не менее я все равно рекомендую включать аннотации типов. Будущий переход к типу float
, как в команде spam
=
42.0
, также изменит автоматически определяемый тип, что может противоречить вашим намерениям. Лучше заставить программиста изменить аннотацию типа при изменении значения, чтобы он подтвердил, что из- менение было внесено намеренно, а не случайно.
228
Глава 11.Комментарии, doc-строки и аннотации типов
Статические анализаторы
Хотя Python поддерживает синтаксис аннотаций типов, интерпретатор Python полностью их игнорирует. Если вы запустите программу Python, которая передает функции переменную с неправильным типом, Python будет вести себя так, словно аннотации типа не существует. Иначе говоря, аннотации типов не заставляют ин- терпретатор Python выполнять какую-либо проверку типов на стадии выполнения.
Аннотации типов существуют только для средств статической проверки типов, которые анализируют код до запуска программы, а не во время выполнения.
Эти средства называются средствами статического анализа, потому что они ана- лизируют исходный код до запуска программы, тогда как средства динамического анализа работают с уже запущенными программами. (В данном случае термины
«статический» и «динамический» относятся к тому, выполняется ли программа, но под терминами «статическая типизация» и «динамическая типизация» понимается способ объявления типов данных переменных и функций. Python является языком с динамической типизацией, для которого были написаны средства статического анализа — такие как Mypy.)
Установка и запуск Mypy
Хотя у Python нет официальных средств проверки типов, из сторонних разработок в настоящее время наибольшей популярностью пользуется Mypy. Чтобы установить
Mypy с помощью pip
, выполните следующую команду:
python –m pip install –user mypy
В macOS и Linux выполните команду python3
вместо python
. Среди других популяр- ных систем проверки типов можно выделить Pyright (Microsoft), Pyre (Facebook) и Pytype (Google).
Чтобы запустить программу проверки типов, откройте окно командной строки или терминала и выполните команду python
-m mypy
(чтобы запустить модуль как приложение) с именем проверяемого файла с кодом Python. В следующем примере проверяется код программы из файла с именем example.py
:
C:\Users\Al\Desktop>python –m mypy example.py
Incompatible types in assignment (expression has type "float", variable has type "int")
Found 1 error in 1 file (checked 1 source file)
Программа не выводит ничего, если ошибки не найдены, и выводит сообщения об ошибках в противном случае. В файле example.py проблема обнаруживается в строке 171, потому что переменная с именем spam имеет аннотацию типа int
, но
Аннотации типов
229
ей присваивается значение float
. Это присваивание способно привести к ошибке, и к нему стоит присмотреться. Некоторые сообщения об ошибках трудно понять с первого взгляда. В сообщениях Mypy могут упоминаться многочисленные воз- можные ошибки — слишком многочисленные, чтобы перечислять их здесь. Чтобы понять, что означает та или иная ошибка, проще всего поискать информацию в интернете.
Запускать Mypy из командной строки при каждом изменении кода неэффективно.
Чтобы пользоваться средствами проверки типов было удобнее, необходимо настро- ить IDE или текстовый редактор так, чтобы эти средства выполнялись в фоновом режиме. В этом случае редактор будет постоянно запускать Mypy при вводе кода, а затем выводить найденные ошибки в редакторе. На рис. 11.1 изображена ошибка из предыдущего примера в текстовом редакторе Sublime Text.
Рис. 11.1. Ошибки Mypy в текстовом редакторе Sublime Text
Конкретная последовательность действий по настройке IDE или текстового редак- тора для работы с Mypy зависит от того, в каком редакторе или IDE вы работаете.
Инструкции можно найти в интернете — используйте условие поиска «<ваша IDE>
Mypy настройка» («
Подавление обработки кода в Mypy
Представьте, что вы написали блок кода, для которого по какой-то причине вы не получаете предупреждения, относящиеся к аннотациям типов. С точки зрения средств статического анализа в строке вроде бы используется неправильный тип, но вы уверены, что во время выполнения эта строка будет работать правильно.
Чтобы подавить любые предупреждения о типах, добавьте комментарий
#
type:
ignore в конец строки. Пример:
230
Глава 11.Комментарии, doc-строки и аннотации типов def removeThreesAndFives(number: int) -> int:
number = str(number) # type: ignore
number = number.replace('3', '').replace('5', '') # type: ignore
return int(number)
Чтобы удалить из целого числа, передаваемого removeThreesAndFives()
, все циф- ры 3 и 5, мы временно преобразуем целочисленную переменную в строку. Из-за этого программа проверки типов выдает предупреждения о двух первых строках функции, поэтому в эти строки добавляются аннотации типов
#
type:
ignore для подавления предупреждений.
Пользуйтесь директивами
#
type:
ignore осмотрительно. Игнорирование преду- преждений от средств проверки типов открывает возможности для проникновения ошибок в ваш код. Код почти всегда можно переписать так, чтобы предупреждения не выдавались. Например, если создать новую переменную командой numberAsStr
=
str(number)
или заменить все три строки кода одной строкой return int(str(number.
replace('3',
'').replace('5',
'')))
, можно избежать повторного использования переменной number для разных типов. Не следует подавлять предупреждения, из- меняя аннотацию типа для этого параметра на
Union[int,
str]
, потому что этот параметр предназначен только для целых чисел.
Аннотации типов для набора типов
Переменные, параметры и возвращаемые значения Python могут принимать разные типы данных. Чтобы учесть эту возможность в программе, следует задать аннотации типов с несколькими типами; для этого надо импортировать
Union из встроенного модуля typing
. Набор допустимых типов задается в квадратных скобках после имени класса
Union
:
from typing import Union spam: Union[int, str, float] = 42
spam = 'hello'
spam = 3.14
В этом примере аннотация
Union[int,
str,
float]
указывает, что переменной spam может быть присвоено целое число, строка или число с плавающей точкой. Обра- тите внимание: лучше использовать форму команды импортирования from typing import
X вместо import typing
, а затем последовательно использовать развернутую форму typing.
X для аннотаций типов во всей программе.
Можно указать несколько типов данных в ситуациях, когда переменная или воз- вращаемое значение могут принимать значение
None в дополнение к другому типу. Чтобы включить
NoneType
(тип значения
None
) в аннотацию типа, укажите в квадратных скобках
None вместо
NoneType
. (Формально
NoneType не является встроенным идентификатором, каким является int или str
.)
Аннотации типов
231
Еще лучше вместо
Union[str,
None]
импортировать
Optional из модуля typing и использовать запись
Optional[str]
. Эта аннотация типа означает, что функция или метод может вернуть
None вместо значения ожидаемого типа. Пример:
from typing import Optional lastName: Optional[str] = None lastName = 'Sweigart'
Здесь переменной lastName может быть присвоено значение str или
None
. Тем не менее к использованию
Union и
Optional стоит подходить осмотрительно. Чем меньше типов допускают ваши переменные и функции, тем проще будет ваш код, а в простом коде реже возникают ошибки, чем в сложном. Вспомните тезис «Дзен
Python»: простое лучше, чем сложное. Если функция возвращает
None как признак ошибки, рассмотрите возможность замены кода ошибки исключением (см. раздел
«Выдача исключений и возвращение кодов ошибок», с. 214).
Чтобы указать, что переменная, параметр или возвращаемое значение может иметь любой тип данных, используйте аннотацию типа
Any
(также из модуля typing
):
from typing import Any import datetime spam: Any = 42
spam = datetime.date.today()
spam = True
В этом примере аннотация типа
Any позволяет вам присвоить переменной spam значение любого типа данных — например, int
, datetime.date или bool
. Также в качестве аннотации типа можно использовать object
, потому что этот класс яв- ляется базовым для всех типов данных Python. Тем не менее аннотация типа
Any лучше читается, чем object
Any
, как и
Union и
Optional
, следует использовать осмотрительно. Назначив всем пере- менным, параметрам и возвращаемым значениям аннотацию типа
Any
, вы лишитесь преимуществ проверки типов, которые предоставляет статическая типизация. Разница между аннотацией типа
Any и отсутствием аннотации состоит в том, что
Any явно со- общает, что переменная или функция принимает значения любого типа, тогда как от- сутствие аннотации означает, что переменная или функция пока еще не аннотированы.
Аннотации типов для списков, словарей и т. д.
Списки, словари, кортежи, множества и другие контейнерные типы данных могут содержать другие значения. Если вы укажете список (
list
) как аннотацию типа для переменной, эта переменная должна содержать список, но тот в свою очередь может содержать значения произвольного типа. Следующий код не вызовет никаких протестов у программы проверки типов:
spam: list = [42, 'hello', 3.14, True]