Существует ли консенсус относительно того, что должно быть задокументировано в классах и строках документации __init__?

Я не нашел никаких рекомендаций относительно того, что должно быть задокументировано в классах и __init__ строках документации. Иногда я обнаруживаю, что аргументы конструктора уже задокументированы в строке документации классов, иногда они описаны в строке документации __init__. Я предпочитаю описывать конструкцию в строке документации классов, так как это то, что вы вызываете при создании нового экземпляра. Но что тогда должно быть задокументировано в строке документации методов __init__?


изменить:

Я знаю о руководстве по стилю Google и пример строки документации Google, но оба не отвечают на мой вопрос. Пример стиля строки документации говорит

Метод __init__ может быть задокументирован либо в строке документации уровня класса, либо в виде строки документации самого метода __init__. Любая форма приемлема, но их не следует смешивать. Выберите одно соглашение для документирования метода __init__ и соблюдайте его.

Но если я решу поместить строку документации функции __init__ в строку документации уровня класса, что должна содержать строка документации __init__?


person causa prima    schedule 04.05.2016    source источник


Ответы (7)


Существует официальный ответ в PEP 257 (строка документации PEP), который возможно, является авторитетным:

Конструктор класса должен быть задокументирован в строке документации для его метода __init__.

Это вполне логично, так как это обычная процедура для функций и методов, и __init__() не исключение.

Как следствие, это помещает код и его документацию в одно и то же место, что облегчает обслуживание.

Наконец, инструменты, которые отображают документацию для пользователя (например, Jupyter или встроенная команда оболочки Python help()), с большей вероятностью правильно отобразят документацию вашего кода. На практике они действительно автоматически отображают строку документации __init__(), когда вы запрашиваете помощь по классу, так что это еще одна причина следовать официальному соглашению о размещении документации по инициализации в __init__().

person Eric O Lebigot    schedule 13.09.2019
comment
К сожалению, конечный пользователь никогда не найдет эту документацию, так как он наберет help(MyClass), а не help(MyClass.__init__), когда застрянет. Так что лично я считаю, что PEP не делает наилучшего предложения, а только следует правилам. Было бы разумно, если бы строка документации help(MyClass) имела механизм включения/отображения строки документации init. - person Demis; 30.09.2019
comment
К счастью, этот комментарий неверен: help(MyClass) показывает все методы класса, а __init__() — один из них, поэтому у пользователя есть информация, необходимая для создания объектов. Это соответствует официальному требованию. Кроме того, такой инструмент, как блокнот Jupyter, делает нечто подобное, когда вы запрашиваете аргументы конструктора класса (с помощью Shift+Tab): он отображает как класс , так и строку документации инициализации. Мораль заключается в том, что следование некоторым общепринятым правилам очень полезно, особенно если они хорошие. - person Eric O Lebigot; 02.10.2019
comment
Вы правы, тогда предложение PEP довольно хорошее. Мне по-прежнему не нравится прокручивать до __init__() в выводе справки - опять же, это функция, которую конечный пользователь никогда не увидит, но ожидается, что она знает, что вместо этого она невидимо переназначается на имя класса. С точки зрения удобочитаемости/очевидности документа это немного уродливо, но я думаю, это просто программирование для вас. Спасибо за исправление, я просто напишу см. __init__() в строке документации моего класса для нубов (многие из которых будут использовать мои модули). - person Demis; 14.12.2019
comment
И Jupyter (до MyClass?), и Python (до help(MyClass)) автоматически отображают строку документации инициализации, так что это должно быть довольно очевидно. Поскольку это стандарт, вполне вероятно, что пользователи увидят его и во многих других библиотеках. - person Eric O Lebigot; 15.12.2019
comment
Интересное дополнение: Spyder автоматически использует содержимое ClassName.__doc__ для автодополнения Tab при создании экземпляра класса, а НЕ содержимое ClassName.__init__.__doc__. Так что это делает документирование в классе гораздо более полезным для конечного пользователя. Также, как говорили другие, NumpyDoc также говорит о конструкторе документов в строке документации класса. Наконец, help(MyClass) не помещает справку __init__ вверху, что делает поиск аргументов конструктора раздражающим! - person Demis; 16.12.2019
comment
Я бы сказал, что и Spyder, и NumpyDoc упустили тот факт, что существует соглашение, которое приводит к нежелательным результатам, которые вы наблюдали. Лично я не возражаю против того, чтобы help(MyClass) поместить __init__() строку документации внизу, так как команда действительно запрашивает помощь по классу, и поэтому информация о том, что предоставляет класс, должна быть первой. Какие бы соглашения ни выбрали программы, обеспечивающие помощь, единственный способ добиться хорошего и последовательного поведения для всех — следовать стандартам. - person Eric O Lebigot; 19.12.2019
comment
Должна быть PythonStudio. - person Brian Wiley; 20.12.2020

Фактическое использование класса инициализируется такой командой, как SampleClass(args), и ни один пользователь никогда не собирается вводить SampleClass.__init__(args), поэтому с точки зрения конечного пользователя, когда он запутался, он с гораздо большей вероятностью наберет

help(SampleClass)

вместо

help(SampleClass.__init__)

Поэтому я думаю, что имеет смысл поместить всю документацию в строку документации SampleClass.
А в строку документации __init__ добавить "Пожалуйста, см. help(SampleClass) для получения дополнительной информации" на случай, если кто-то (или какая-то программа) ) смотрит на это.

person Demis    schedule 09.10.2018
comment
Пользователь указал, что help(SampleClass) ТАКЖЕ распечатывает справку для SampleClass.__init__(), но, к сожалению, Spyder показывает эту строку внизу списка методов. Теоретически документирования конструктора в init__() было бы достаточно, за исключением того, что он все еще сбивает с толку, поскольку снова пользователь никогда не видит термин __init__ и должен знать, что он незримо переназначается на MyClass(args)). В этом комментарии: stackoverflow.com/questions/37019744/ - person Demis; 03.06.2021

Я лично стараюсь использовать руководство по стилю Google, когда это возможно.

Когда вы создаете новый экземпляр с помощью __init__, необходимо документировать, какие переменные-члены инициализируются. Тогда другие люди узнают, чего им ожидать, когда им потребуется получить к ним доступ позже в своем коде.

Пример из руководства по стилю Google:

class SampleClass(object):
    """Summary of class here.

    Longer class information....
    Longer class information....

    Attributes:
        likes_spam: A boolean indicating if we like SPAM or not.
        eggs: An integer count of the eggs we have laid.
    """

    def __init__(self, likes_spam=False):
        """Inits SampleClass with blah."""
        self.likes_spam = likes_spam
        self.eggs = 0

    def public_method(self):
        """Performs operation blah."""
person salomonderossi    schedule 04.05.2016
comment
Я тоже пытаюсь использовать это руководство, но оно не отвечает на мой вопрос, как я указал в своем обновленном вопросе. - person causa prima; 04.05.2016
comment
imho, вы должны документировать, какие переменные-члены (которые не являются частными) инициализируются. Тогда другие люди знают, чего они могут ожидать, когда получат к ним доступ. - person salomonderossi; 04.05.2016
comment
верный момент, но этот ответ не имеет ничего общего с вопросом - person Günther Jena; 09.07.2018

Документация класса должна включать общедоступные компоненты объекта. Параметры __init__ могут быть общедоступными, а могут и не быть, поэтому то, будут ли они включены в строку документации класса или нет, зависит от конструкции объекта.

Полный абзац в PEP 257 гласит:

Строка документации для класса должна обобщать его поведение и перечислять общедоступные методы и переменные экземпляра. Если класс предназначен для создания подклассов и имеет дополнительный интерфейс для подклассов, этот интерфейс должен быть указан отдельно (в строке документации). Конструктор класса должен быть задокументирован в строке документации для его метода __init__. Отдельные методы должны быть задокументированы их собственной строкой документации.

А в руководстве по стилю Google говорится:

Классы должны иметь строку документации под определением класса, описывающим класс. Если у вашего класса есть общедоступные атрибуты, они должны быть задокументированы здесь в разделе «Атрибуты» и иметь такое же форматирование, как и раздел «Аргументы» функции.

Таким образом, определение документации зависит от того, являются ли параметры для __init__ общедоступными. Если целью объекта является создание пользователями собственных экземпляров, параметры __init__ должны быть задокументированы в строке документации класса. Однако, если объект создается внутри, а затем возвращается пользователю, документация класса должна ссылаться только на общедоступные аспекты объекта.

Таким образом, следующий пример из Google предполагает, что параметр likes_spam из __init__ является общедоступным:

class SampleClass(object):
    """Summary of class here.

    Longer class information....
    Longer class information....

    Attributes:
        likes_spam: A boolean indicating if we like SPAM or not.
        eggs: An integer count of the eggs we have laid.
    """

    def __init__(self, likes_spam=False):
        """Inits SampleClass with blah."""
        self.likes_spam = likes_spam
        self.eggs = 0

    def public_method(self):
        """Performs operation blah."""

Однако ниже общедоступный атрибут likes_spam определяется во время __init__ на основе двух внутренних параметров spam_count и like_threshold. Таким образом, likes_spam задокументировано в строке документации класса, а spam_count и like_threshold — в строке документации __init__.

class SampleClass(object):
    """Summary of class here.

    Longer class information....
    Longer class information....

    Attributes:
        likes_spam: A boolean indicating if we like SPAM or not.
        eggs: An integer count of the eggs we have laid.
    """

    def __init__(self, spam_count, like_threshold=1):
        """Inits SampleClass.

        Args:
            spam_count: The amount of SPAM consumed.
            like_threshold: The threshold consumed that indicates 
                whether we like SPAM.
        """
        self.likes_spam = spam_count > like_threshold
        self.eggs = 0

    def public_method(self):
        """Performs operation blah."""
person dshanahan    schedule 25.05.2020

Numpy говорит, что вы должны задокументировать __init__ в документе класса. https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard

Вот пример, где __init__ нет строки документации. Вместо этого он отображается в документе класса. https://github.com/numpy/numpy/blob/master/numpy/core/records.py

person Brig    schedule 18.10.2018
comment
Это противоречит официальному руководству PEP 257. - person Eric O Lebigot; 15.12.2019
comment
Затем Spyder также идет вразрез с официальными рекомендациями, поскольку кажется, что Spyder получает текст автозаполнения вкладок из класса, а не из init. - person Demis; 17.12.2019
comment
Я думаю, мы должны задать вопрос Почему основные пакеты с огромной пользовательской базой делают это иначе, чем рекомендации PEP 257. Я видел, как пользователи SO ссылаются на numpy/numpydoc как на стандарты. Может быть, есть веская причина. Существуют ли другие пакеты, которые также не соответствуют PEP 257? - person Demis; 26.12.2019
comment
@Demis Spyder делает для меня что-то странное. Если я нажму Ctrl+I, он получит строку документации класса. Если я использую function?, он показывает класс, а затем строку документации __call__, но если я набираю function(, отображается всплывающее окно, которое начинается в середине раздела Returns строки документации класса... - person endolith; 26.10.2020
comment
На этот другой вопрос было получено несколько ответов, указывающих на то, что Sphinx анализирует строку документации, но я до сих пор не очень понимаю, как он это делает. stackoverflow.com/review/suggested-edits/25144896 - person Demis; 27.10.2020

Мне не известно о каком-либо консенсусе по этому вопросу.

Однако модуль sphinx autodoc позволяет создавать документацию из вашей строки документации. . Поэтому он имеет тенденцию обеспечивать согласованную документацию docstring.

В вашем случае я бы задокументировал, что такое class и аргументы конструктора в class строке документации, например:

class MyClass:
    """I am a class.
    I do funny stuff

    :type tags: dict
    :param tags: A dictionary of key-value pairs
    """

    def __init__(tags):
        self.tags = tags
person Oleiade    schedule 04.05.2016
comment
Как я уже сказал, это то, что я бы тоже предпочел. Но поскольку большинство руководств рекомендуют вам также писать строки документации для специальных функций, мне интересно, что должна содержать строка документации __init__, поскольку все, что она должна делать, это инициализировать экземпляр класса. Кроме того, с такими инструментами, как sphinx, информация, написанная в строке документации специальных функций, не будет отображаться в встроенной документации, если я не ошибаюсь. - person causa prima; 04.05.2016
comment
Ну, поскольку нет единого мнения по этому вопросу, и, насколько я знаю, никакая официальная документация по Python не решает эту проблему. Я бы сказал, делайте так, как считаете нужным. Я думаю, что реальный вопрос здесь заключается в том, почему вы хотите тогда добавить строку документации к специальным функциям (с какой целью)? Я имею в виду в каком контексте? Это для документирования кода, для создания документов? - person Oleiade; 04.05.2016

У Google есть собственное руководство по стилю для Python, на которое стоит обратить внимание. Вот ссылка на то, что они считают лучшими практиками для строк документов: http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html

person coralvanda    schedule 04.05.2016
comment
Они не отвечают на мой вопрос, как я указал в своем обновленном вопросе. - person causa prima; 04.05.2016
comment
Из вашего обновленного вопроса: но если я решу поместить строку документации функции init в строку документации уровня класса, что должна содержать строка документации init? Согласно руководству по стилю, в этом случае у вашего метода init не должно быть строки документации. - person coralvanda; 04.05.2016