Как мне задокументировать конструктор для класса с использованием классов данных Python?

У меня есть существующий код Python 3.6, который я хотел бы перенести на классы данных Python 3.7. У меня есть __init__ методы с хорошей документацией, в которой указаны атрибуты, которые принимают конструкторы, и их типы.

Однако, если я изменю эти классы для использования новых классов данных Python в версии 3.7, конструктор будет неявным. Как мне предоставить конструкторскую документацию в этом случае? Мне нравится идея классов данных, но не в том случае, если мне придется отказаться от четкой документации для их использования.

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


person anahata    schedule 01.07.2018    source источник
comment
Кажется, что классы данных автоматически генерируют строку документации для класса, которая включает подсказки типа из определения класса, например 'C(name: str, number: int)', но строка документации для автоматически сгенерированного метода __init__ - это None. Итак, я полагаю, вы могли бы вручную назначить __init__ docstring после определения класса. Хотя немного неуклюже.   -  person snakecharmerb    schedule 01.07.2018
comment
Эта автоматически сгенерированная строка документации не отображается, если у меня уже есть строка документации для класса, и это нормально, потому что предоставленная человеком строка документации (обычно!) Намного лучше, чем автоматически созданная. Назначение строки документации вручную определенно неуклюже, и я бы хотел избежать этого, если это возможно, отсюда и этот вопрос.   -  person anahata    schedule 01.07.2018
comment
Верно по обоим пунктам. Кроме того, назначенная вручную строка документации будет работать для инструментов времени выполнения, таких как help, но, возможно, не для генераторов документации, таких как Sphinx.   -  person snakecharmerb    schedule 01.07.2018


Ответы (3)


Строки документов в стиле наполеона, как они описаны в документах по сфинксу (см. класс ExampleError, чтобы узнать об этом) явно коснитесь вашего случая:

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

И если вы не хотите такого поведения, вам необходимо явно указать sphinx, что строка документации конструктора и строка документации класса - это не одно и то же.

Это означает, что вы можете просто вставить информацию о конструкторе в тело строки документации класса.


В случае, если вы создаете документы из своих строк документации, вот детали, которые могут быть достигнуты:

1) Самый минимум:

@dataclass
class TestClass:
    """This is a test class for dataclasses.

    This is the body of the docstring description.
    """
    var_int: int
    var_str: str

введите описание изображения здесь

2) Дополнительное описание параметра конструктора:

@dataclass
class TestClass:
    """This is a test class for dataclasses.

    This is the body of the docstring description.

    Args:
        var_int (int): An integer.
        var_str (str): A string.

    """
    var_int: int
    var_str: str

введите описание изображения здесь

3) Описание дополнительного атрибута:

@dataclass
class TestClass:
    """This is a test class for dataclasses.

    This is the body of the docstring description.

    Attributes:
        var_int (int): An integer.
        var_str (str): A string.

    """
    var_int: int
    var_str: str

введите описание изображения здесь


Описания параметров и атрибутов, конечно, также можно комбинировать, но поскольку классы данных должны быть прямыми сопоставлениями, я не вижу причин для этого.

На мой взгляд, 1) подойдет для небольших или простых классов данных - он уже включает сигнатуру конструктора с соответствующими типами, чего достаточно для класса данных. Если вы хотите подробнее рассказать о каждом атрибуте, лучше всего подойдет 3).

person Arne    schedule 02.07.2018
comment
Это восхитительно подробно, спасибо! Я особенно ценю ссылку на документы Sphinx, которые охватывают именно этот случай. - person anahata; 02.07.2018
comment
Рад, что помог тебе =) - person Arne; 02.07.2018
comment
@Arne bro, какую конфигурацию для Sphinx вы используете? Я не могу создать документацию по атрибутам, как в третьем примере. - person woozly; 10.04.2020
comment
@woozly Я только что повторно запустил то, что, по моему мнению, было моим образцом cpde, и не могу заставить их выглядеть так же. Может быть, сфинкс изменил то, как они относятся к классам данных? Во всяком случае, все мои conf.py выглядят более или менее (просто переключите тему на "alabaster", чтобы увидеть здесь сообщение), и документы будут созданы , как описано здесь. - person Arne; 10.04.2020
comment
@Arne, спасибо! У меня он работал с включенным расширением sphinx.ext.napoleon. - person woozly; 11.04.2020
comment
@Arne У меня аналогичная конфигурация, и моя проблема в том, что я дважды получаю поля в документах, один раз с моей строкой документации, а другой автоматически сгенерирован с подсказками типов - person magomar; 28.10.2020
comment
@magomar Вы правы, я просто перезапустил его код и также получаю повторяющиеся описания переменных, которых раньше не было. Этот ответ теперь устарел, поскольку сфинкс начал особую обработку классов данных. - person Arne; 29.10.2020
comment
исправление - все классы теперь получают свои classvars прослушивания в строке документации, отображаемой sphinx, а не только dataclasses. Я отслеживаю это в этих новых вопросах и буду обновите этот ответ соответствующим образом. - person Arne; 29.10.2020
comment
@bad_coder Грасиас, lo acabo de ver. Lo tengo que estudiar más despacio, pero dado que genero los rst de forma automática no creo que me resultw practico tener que añadir excepciones para cada dataclass - person magomar; 30.10.2020

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

@dataclass
class InventoryItem:
    '''Class for keeping track of an item in inventory.'''
    name: str
    unit_price: float
    quantity_on_hand: int = 0

    def total_cost(self) -> float:
        return self.unit_price * self.quantity_on_hand

Если вы не ожидаете, что читатели вашего кода будут знать, как работают классы данных, вы можете пересмотреть их использование или добавить объяснение или ссылку на документы во встроенном комментарии после декоратора @dataclass. Если вам действительно нужна строка документации для класса данных, я бы рекомендовал поместить строку документации конструктора в строку документации класса. В приведенном выше примере:

'''Class for keeping track of an item in inventory.

Constructor arguments:
:param name: name of the item
:param unit_price: price in USD per unit of the item
:param quantity_on_hand: number of units currently available
'''
person orn688    schedule 01.07.2018
comment
Хм. Это делает больший акцент на важности наименования ваших атрибутов, если они действительно будут самодокументированными. Спасибо за предложения! - person anahata; 01.07.2018
comment
@ orn688 Но можно ли полностью исключить dataclass из документации? - person Dmytro Chasovskyi; 06.01.2020
comment
Стоит отметить, что help(InventoryItem) не будет отображать атрибуты name, unit_price или quantity_on_hand или их строки документации. - person Mike Holler; 13.02.2020

Думаю, самый простой способ:

@dataclass
class TestClass:
    """This is a test class for dataclasses.

    This is the body of the docstring description.

    """
    var_int: int  #: An integer.

    #: A string.
    #: (Able to have multiple lines.)
    var_str: str

    var_float: float
    """A float. (Able to have multiple lines.)"""

Не знаю, почему результаты, обработанные @Arne, выглядят так. В моем случае атрибуты в классе данных всегда будут отображаться независимо от строки документации. Это:

1) Самый минимум:

2) Дополнительное описание параметра конструктора:

3) Описание дополнительного атрибута:

Вероятно, потому что я что-то неправильно установил в своем conf.py (Sphinx v3.4.3, Python 3.7):

extensions = [
    "sphinx.ext.napoleon",
    "sphinx.ext.autodoc",
    "sphinx_autodoc_typehints",
    "sphinx.ext.viewcode",
    "sphinx.ext.autosectionlabel",
]

# Napoleon settings
napoleon_google_docstring = True
napoleon_include_init_with_doc = True
person edxu96    schedule 12.02.2021
comment
Не уверен, почему результаты, обработанные @Arne, выглядят так - ›Что-то изменилось в том, как sphinx отображал атрибуты по умолчанию: stackoverflow.com/q/64588821 / 962190 - person Arne; 19.05.2021