Перейти к содержанию

412 уроков, 25 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 18 из 20 Начальный 15 мин 100 XP

docstring в Python: документация внутри функции

Документация живёт внутри функции: строка в тройных кавычках после def, атрибут __doc__ и честный формат короткого описания.

Редакция Питоники

Функцию пишет один человек, а читают — другие, включая вас через полгода. Имя и аннотации из прошлого урока говорят, что принимает и возвращает функция, но не говорят, что она делает и в каких пределах думает. Для этого в Python есть docstring — строка документации, которая живёт прямо внутри функции. Это не комментарий мимо кода, а часть самой функции: её можно достать программно, и на неё опирается справка.

Первая документация: строка сразу после def

docstring — это строка в тройных кавычках сразу после def: она живёт в атрибуте __doc__ и попадает в справку help(). Тройные кавычки нужны на случай многострочного текста; короткое описание умещается и в одну строку.

первая строка документации
def celsius_to_fahrenheit(celsius):
    """Переводит градусы Цельсия в Фаренгейты."""
    return celsius * 1.8 + 32

print(celsius_to_fahrenheit(100))
print(celsius_to_fahrenheit.__doc__)
Вывод
212.0
Переводит градусы Цельсия в Фаренгейты.

Атрибут __doc__ — обычная строка, приклеенная к функции: её можно напечатать, измерить длиной, передать дальше. Python положил туда docstring автоматически, ничего присваивать не пришлось. Обратите внимание: печать идёт напрямую из атрибута, без справочной системы.

Многострочный docstring и чистый текст

Длинное описание пишут в несколько строк: первая — короткое резюме, дальше — аргументы и результат. Внутри __doc__ строка хранится как написано, вместе с отступами, поэтому для аккуратной печати подключают inspect.getdoc из стандартной библиотеки — он возвращает чистый текст без лишних отступов:

многострочный формат
import inspect

def normalize_spaces(text):
    """Сжимает повторы пробелов в один.

    Аргументы:
        text: строка, которую надо почистить.

    Возвращает:
        строку без лишних пробелов.
    """
    return ' '.join(text.split())

print(normalize_spaces('  привет    мир  '))
print(inspect.getdoc(normalize_spaces))
Вывод
привет мир
Сжимает повторы пробелов в один.

Аргументы:
    text: строка, которую надо почистить.

Возвращает:
    строку без лишних пробелов.

Печатный текст совпал с написанным — тот же порядок, те же строки. Разделы с Аргументами и результатом — не жёсткий синтаксис, а хорошая привычка: любой человек прочёл описание и знает, что функция вернёт, не открывая тело.

справка через help()
help(len)
help() открывает интерактивный пейджер и ждёт нажатий клавиш, поэтому на странице не запускается. В терминале он печатает справку, собранную из docstring функции. В блоках урока мы достаём документацию напрямую — через __doc__ и inspect.getdoc, это обычные строки без пейджера.

docstring против комментария

Комментарий со решёткой и docstring живут рядом, но служат разному. Комментарий объясняет код тому, кто его правит; docstring объясняет функцию тому, кто её вызывает. Инструменты видят только docstring — вот функции с одинаковым телом и разной документацией:

хороший и пустой docstring
def slugify(title):
    """Превращает заголовок в слаг для ссылки."""
    return title.lower().replace(' ', '-')

def process(title):
    """обрабатывает строку"""
    return title.lower().replace(' ', '-')

print(slugify('Мой Первый Пост'))
print(process('Мой Первый Пост'))
Вывод
мой-первый-пост
мой-первый-пост

Машина выдала одинаковый результат — тела идентичны. Разница для человека: по документации slugify понятно, что вернётся и зачем; process обещает «обработку», то есть ничего не обещает. docstring пишут для вызова, а не для компилятора.

docstring строго привязан к месту: документацией становится только строка, стоящая первой в теле. Любое выражение раньше неё — и атрибут __doc__ останется пустым, точнее None:

строка не на первом месте
def broken():
    result = 1
    """Эта строка не docstring: она не первая в теле."""
    return result

print(broken.__doc__)
Вывод
None

Что писать в docstring

Формат короткого описания из трёх частей: первая строка — глагол и суть; раздел Аргументов — по строке на каждый; раздел Возврата — что получит вызывающий:

полный формат описания
import inspect

def discount(price, percent):
    """Считает цену со скидкой.

    Аргументы:
        price: цена до скидки.
        percent: скидка в процентах.

    Возвращает:
        цену после скидки.
    """
    return price * (100 - percent) / 100

print(discount(500, 20))
print(inspect.getdoc(discount))
Вывод
400.0
Считает цену со скидкой.

Аргументы:
    price: цена до скидки.
    percent: скидка в процентах.

Возвращает:
    цену после скидки.

Пример достаточно короткий, чтобы читать его глазами, и достаточно честный, чтобы не лезть в тело. Для функций-однострочников хватит и одной строки — как у celsius_to_fahrenheit: многострочность нужна, когда есть что объяснить про аргументы.

РазделЧто писатьПример
Первая строкаОдин глагол и сутьСчитает цену со скидкой
АргументыПо строке на аргумент: имя и смыслprice: цена до скидки
ВозвратЧто получит вызывающийцену после скидки
ТипыЕсли аннотаций нет — укажи словамиprice: целое число

Длину документации можно измерить прямо — __doc__ это строка, и len работает:

документация под меркой
def area(width, height):
    """Площадь прямоугольника: ширина на высоту."""
    return width * height

print(area(3, 4))
print(len(area.__doc__))
Вывод
12
41

Почему у lambda нет документации

lambda из урока про lambda — функция без имени, и docstring в ней не написать: тело — одно выражение, первой строкой там не разразишься документацией. Это ещё один аргумент за def, когда функцию будут читать чужие:

lambda без документации
def doubled(n):
    """Возвращает удвоенное число."""
    return n * 2

double = lambda x: x * 2

print(doubled(3), double(3))
print(double.__doc__)
Вывод
6 6
None
примеры-тесты внутри docstring
if __name__ == '__main__':
    import doctest
    doctest.testmod()
Фрагмент: модуль doctest находит в docstring строки с примерами >>> и прогоняет их как тесты. Пример в документации одновременно проверяет код — приём для библиотек, о нём финальный проект курса.
  • первая строка — глагол: Переводит, Считает, Превращает; без слов «функция» и «данная» — их видно и так;
  • аргументы — по строке на каждый: имя и смысл, а не тип, если он уже стоит в аннотации;
  • возврат — одной строкой: что получит вызывающий, особенно если возможен None;
  • коротко: docstring, который длиннее тела функции, — сигнал, что описание надо сжать.

Документация закончила образ функции: имя, аннотации и docstring — три строки визитки, по которым функцию можно вызвать, не читая тело. Остался последний стройный навык — ошибки: что происходит, когда вызов не совпал с такой визиткой. Следующий урок разбирает TypeError и его друзей.

docstring у класса и метода

Документация есть не только у функций. У класса docstring пишется сразу после строки class, у метода — сразу после def. Это первое, что читают, когда открывают чужой модуль: что это за объект и зачем он.

описание у класса и метода
class Report:
    """Отчёт по продажам за месяц."""

    def __init__(self, title):
        """Создаёт отчёт с заголовком."""
        self.title = title

    def line(self, value):
        """Возвращает строку отчёта для одного значения."""
        return f'{self.title}: {value}'

print(Report.__doc__)
print(Report.line.__doc__)
Вывод
Отчёт по продажам за месяц.
Возвращает строку отчёта для одного значения.

У каждого объекта свой __doc__: у класса — про класс, у метода — про метод. Ничего общего с __init__ это не имеет — конструктор здесь просто обычная функция, которой досталась собственная документация. У встроенных типов документация есть тоже: print(str.__doc__) покажет, что умеет строка.

Как читают чужую документацию

Документация — текст, который пишут для других, и читают её тремя способами. Первый — навести курсор на имя функции в редакторе: всплывающая подсказка покажет первую строку docstring, если он есть. Второй — help(функция) в терминале: полная справка с сигнатурой и описанием, с возможностью листать. Третий — print(inspect.getdoc(функция)): чистый текст без пейджера, удобно, когда разбираешь чужой код в блокноте.

Третий способ мы уже использовали в блоках урока — и сделали это специально: печать через __doc__ и inspect.getdoc даёт обычные строки, которые можно сравнить, сохранить в файл или показать в отчёте. help() на странице не запускается: он открывает интерактивный пейджер и ждёт нажатий клавиш.

Что писать, а что не писать

Не пишем в docstringПочему
«Функция складывает числа»Это видно из имени и из подписи — вызывающему нужно другое
Копию аннотаций типовТипы уже стоят в заголовке, повторять их — шум
Историю проекта и планы на будущееЭто не про функцию, а про проект: такое живёт в README
Списки задач вида TODOОбещание читателю даёт поведение, а не список дел
Подробный разбор алгоритмаЭто объяснение кода — ему место в комментарии

Рабочее правило простое: docstring отвечает на вопрос «как мне этим пользоваться», а не «как это устроено внутри». Всё, что видно из подписи, повторять не надо. И наоборот — если из имени и подписи неясно, что вернётся при пустых данных или при None, это стоит написать.

doctest: примеры в документации проверяются

В Python есть приём, который мы в команде полюбили: примеры внутри docstring можно прогнать как тесты. Строка, начинающаяся с >>>, — это вызов, а следующая строка — ожидаемый результат.

пример в docstring как тест
import doctest

def double(n):
    """Удваивает число.

    >>> double(3)
    6
    """
    return n * 2

print(doctest.testmod())
Вывод
TestResults(failed=0, attempted=1)

Результат читается прямо: failed=0, attempted=1 — один пример, ни одной ошибки. Если код разъедется с документацией, doctest покажет расхождение прямо в тексте. Мы держим правило: у публичной функции с нетривиальным поведением в docstring есть хотя бы один пример. Он стоит три строки и заменяет половину вопросов «а как это работает».

Практика: визитка функции целиком

Соберём вместе всё, что мы знаем о функции: имя, аннотации типов и документацию. Это и есть та самая визитка, по которой функцию вызывают, не открывая тело.

подпись, описание и пример
import inspect

def average_price(prices: list[int]) -> float:
    """Считает среднюю цену по списку.

    Аргументы:
        prices: список цен в рублях.

    Возвращает:
        среднее арифметическое по списку.
    """
    return sum(prices) / len(prices)

print(average_price([100, 200, 300]))
print(inspect.getdoc(average_price))
Вывод
200.0
Считает среднюю цену по списку.

Аргументы:
    prices: список цен в рублях.

Возвращает:
    среднее арифметическое по списку.

Аннотация отвечает на вопрос «какие типы», docstring — «что это делает и как этим пользоваться». Вместе они дают достаточно, чтобы вызвать функцию, не открывая её: типы известны, смысл известен, а inspect.getdoc вернёт описание обычной строкой, если нужно его показать или сохранить.

Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

def half(n):
    """Возвращает половину числа."""
    return n / 2

print(half(10))
print(half.__doc__)
def broken():
    result = 1
    """Эта строка не docstring."""
    return result

print(broken.__doc__)
def area(width, height):
    """Площадь прямоугольника: ширина на высоту."""
    return width * height

print(area(3, 4))
print(len(area.__doc__))
Проверь себя
0 / 9

1. Что такое docstring?

2. Как достать документацию функции my_func без справочной системы?

3. Строка в тройных кавычках стоит второй строкой тела, после присваивания. Что в __doc__?

4. Что делает help(функция) в терминале?

5. Чем docstring отличается от комментария #?

6. Что лежит в double.__doc__ у lambda-функции?

7. Где пишется docstring у класса?

8. Что делает doctest.testmod()?

9. Нужно ли писать в docstring то, что уже видно из аннотаций?

Карточки терминов
Запомнено: 0 / 9
Практика

Напиши функцию initials с docstring: она принимает имя и фамилию и возвращает инициалы — первые буквы слов с точками. Напечатай результат и документацию.

practice.py
Вопросы и ответы по уроку

Как посмотреть документацию функции в Python?

Напечатать атрибут __doc__: print(функция.__doc__) — это обычная строка. В терминале работает help(функция): он печатает ту же документацию красиво, через интерактивный пейджер, который закрывается клавишей q.

Урок 17: аннотации типов

Чем docstring отличается от комментария?

Комментарий со решёткой объясняет код тому, кто его правит, и существует только в файле. Docstring — документация для вызывающего: Python хранит её в __doc__, её показывают help() и подсказки редактора. Пользователю функции — docstring, правящему код — комментарий.

Как написать многострочный docstring?

Открыть строку тройными кавычками сразу после def: первая строка — короткое резюме с глаголом, дальше — раздел Аргументов по строке на каждый и раздел Возврата. Для чистой печати подключают inspect.getdoc — он убирает лишние отступы.

Обязателен ли docstring для каждой функции?

Нет, атрибут __doc__ у функции без документации равен None, и код работает как работал. Но у публичной функции — той, которую будут вызывать другие или вы сами из другого файла, — docstring стоит первой строки тела по привычке: визитка дешевле вопросника.

Как посмотреть docstring, не открывая help() с пейджером?

Напечатать атрибут: print(функция.__doc__) — обычная строка без всяких страниц. Для чистого текста без отступов подойдёт inspect.getdoc(функция): результат можно сохранить в файл или показать в отчёте.

Что такое doctest и зачем он нужен?

Модуль стандартной библиотеки, который находит в docstring строки с >>> и проверяет, что примеры дают заявленный результат. doctest.testmod() возвращает счётчик вида TestResults(failed=0, attempted=1). Документация в таком случае проверяется автоматически.

Чем аннотации типов отличаются от docstring по назначению?

Аннотация отвечает на вопрос «какие типы» — её читает редактор и mypy. Docstring отвечает на вопрос «что это делает и как пользоваться» — её читает человек. Вместе они дают полную визитку функции: типы известны, смысл известен.

Понравился урок? Сошлитесь на него

«docstring — это строка в тройных кавычках сразу после def: она живёт в атрибуте __doc__ и попадает в справку help().»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Что дальше

Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.