Як документувати атрибути класу в Python? [зачинено]


115

Я пишу легкий клас, атрибути якого призначені для загальнодоступного доступу, і лише іноді перекриваються в конкретних моментах На мові Python не передбачено створення документів для атрибутів класу чи будь-яких атрибутів. Який очікуваний та підтримуваний спосіб, чи має бути такий, щоб документувати ці атрибути? В даний час я займаюся такою справою:

class Albatross(object):
    """A bird with a flight speed exceeding that of an unladen swallow.

    Attributes:
    """

    flight_speed = 691
    __doc__ += """
        flight_speed (691)
          The maximum speed that such a bird can attain.
    """

    nesting_grounds = "Raymond Luxury-Yacht"
    __doc__ += """
        nesting_grounds ("Raymond Luxury-Yacht")
          The locale where these birds congregate to reproduce.
    """

    def __init__(self, **keyargs):
        """Initialize the Albatross from the keyword arguments."""
        self.__dict__.update(keyargs)

У результаті вийде докстринг класу, що містить початковий стандартний розділ docstring, а також рядки, додані для кожного атрибута за допомогою розширеного призначення __doc__.

Хоча цей стиль не видається прямо забороненим в настановах стилю docstring , він також не згадується як варіант. Перевага тут полягає в тому, що він забезпечує спосіб документування атрибутів поряд з їх визначеннями, створюючи при цьому докстринг презентабельного класу та уникаючи необхідності писати коментарі, що повторюють інформацію з docstring. Мені все одно дратується, що я мушу насправді писати атрибути двічі; Я розглядаю можливість використання рядкових представлень значень у docstring, щоб хоча б уникнути дублювання значень за замовчуванням.

Це грізне порушення тимчасових конвенцій громади? Це добре? Чи є кращий спосіб? Наприклад, можна створити словник, що містить значення та docstrings для атрибутів, а потім додати вміст до класу __dict__та docstring до кінця декларації класу; це зменшило б необхідність вводити імена атрибутів і значення атрибутів двічі. редагувати : ця остання ідея, я думаю, насправді не можлива, принаймні, не без динамічного побудови всього класу з даних, що здається дійсно поганою ідеєю, якщо немає інших причин для цього.

Я досить новачок у python і все ще опрацьовую деталі стилю кодування, тому також непомітна критика також вітається.


Якщо ви шукаєте спосіб документувати атрибути моделі Django, це може бути корисним: djangosnippets.org/snippets/2533
Michael Scheper

3
Дублікат того, як документувати поля та властивості в Python? які мають інше рішення.
bufh

1
Я не розумію, чому це засновано на думці. Python спеціально документує прийнятні конвенції в PEPs. Існують різні інструменти джерела Python, які витягують належним чином відформатовану документацію. Насправді в Python насправді є attribute doc stringзгадка в PEP 257, яка недостатньо відома і здається, що важко знайти, що може відповісти на питання ОП, і підтримується деякими джерелами інструментів. Це не думка. Це факт, і частина мови, і майже все те, що хоче ОП.
NeilG

Відповіді:


83

Щоб уникнути плутанини: термін властивість має конкретне значення в python. Те, про що ви говорите, - це те, що ми називаємо атрибутами класу . Оскільки вони завжди діють через їхній клас, я вважаю, що має сенс документувати їх у рядку doc класу. Щось на зразок цього:

class Albatross(object):
    """A bird with a flight speed exceeding that of an unladen swallow.

    Attributes:
        flight_speed     The maximum speed that such a bird can attain.
        nesting_grounds  The locale where these birds congregate to reproduce.
    """
    flight_speed = 691
    nesting_grounds = "Throatwarbler Man Grove"

Я думаю, що це набагато простіше для очей, ніж підхід у вашому прикладі. Якби я дуже хотів, щоб копія значень атрибутів відображалася в рядку doc, я б розмістив їх біля або нижче опису кожного атрибута.

Майте на увазі, що в Python рядки doc - це фактичні члени об'єктів, які вони документують, а не лише анотації вихідного коду. Оскільки змінні атрибути класу не є самими об'єктами, а посиланнями на об'єкти, вони не мають змоги утримувати власні рядки doc. Я думаю, ви можете зробити випадок для рядків doc за посиланнями, можливо, щоб описати "що тут має йти" замість "що насправді тут", але мені здається, що це досить просто зробити в містять рядок doc класу.


Я думаю, що в більшості випадків це нормально, оскільки атрибути - посилання на термінологічну корекцію - є достатньо лаконічними, що їх можна просто згрупувати на початку декларації класу, не роблячи недоцільним перегортання туди і назад {read both документація та значення за замовчуванням} або {оновити обидва екземпляри документації та / або значення за замовчуванням}.
інтуїтивно

1
Також зауважте, що мій приклад призведе до того, що документація щодо атрибутів з'явиться в документі класу. Я фактично вважаю за краще розмістити документацію в документах самих атрибутів, але це не працює для більшості вбудованих типів.
інтуїтивно

Так, моя первісна ідея полягала в тому, щоб просто заявити, наприклад flight_speed = 691; flight_speed.__doc__ = "blah blah". Я думаю, це саме те, що ви згадуєте у своїй редакції . На жаль, це не працює для екземплярів (більшості?) Вбудованих типів (як intу цьому прикладі). Це працює для екземплярів визначених користувачем типів. =========== Насправді був PEP (вибачте, забудьте номер), який запропонував додати доктрини для атрибутів класу / модуля, але це було відхилено, оскільки вони не могли знайти спосіб зрозуміти чи були доктрини для попередніх або наступних атрибутів.
інтуїтоване

2
то що робити, якщо вони є атрибутами екземпляра? все ще документ у класі docstring чи що?
n611x007

1
@intuited Це був цей ПЕП? legacy.python.org/dev/peps/pep-0224
таз

30

Ви цитуєте PEP257: Docstring Convention, у розділі Що таке docstring зазначено:

Строкові літерали, що зустрічаються в іншому місці в коді Python, можуть також виступати документацією. Вони не розпізнаються компілятором байт-кодів Python і не є доступними як атрибути об'єкта виконання (тобто не присвоєні __doc__), але два типи додаткових документів можуть бути вилучені програмними засобами:

Літеральні рядки, що виникають одразу після простого призначення на верхньому рівні модуля, класу або __init__ методу, називаються "атрибути доктринами".

І це детальніше пояснено в PEP 258: Документи щодо атрибутів. Як пояснено вище ʇsәɹoɈ. атрибут не є об'єктом, який може володіти __doc__, тому вони не відображатимуться в help()pydoc. Ці документи можна використовувати лише для створеної документації.

Вони використовуються в Сфінксі з директивою автозавантаження

Сфінкс може використовувати коментарі до рядка перед призначенням або спеціальний коментар після присвоєння чи докстрингу після визначення, яке буде автодокументовано.


1
Плагін jedi-vim також розпізнає документацію атрибутів.
Лонг Ву

1
Я не знаю, коли це було введено, але Sphinx 1.2.2, здається, включає атрибути в створену документацію.
jochen

1
Дякую @jochen, я оновлюю свою відповідь.
березень

3
Зверніть увагу, що PEP 258 відхилено. У повідомленні про відмову зазначається: "Хоча це може слугувати цікавим дизайнерським документом для тепер незалежних документів, воно більше не планується для включення до стандартної бібліотеки."
Michał Łazowik

13

Ви можете зловживати властивостями з цим ефектом. Властивості містять геттер, сеттер, делтер та докстринг . Наївно, це вийшло б багатослівним:

class C:
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """Docstring goes here."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

Тоді ви будете мати docstring, що належить Cx:

In [24]: print(C.x.__doc__)
Docstring goes here.

Зробити це для багатьох атрибутів громіздко, але ви можете передбачити помічну функцію myprop:

def myprop(x, doc):
    def getx(self):
        return getattr(self, '_' + x)

    def setx(self, val):
        setattr(self, '_' + x, val)

    def delx(self):
        delattr(self, '_' + x)

    return property(getx, setx, delx, doc)

class C:
    a = myprop("a", "Hi, I'm A!")
    b = myprop("b", "Hi, I'm B!")

In [44]: c = C()

In [46]: c.b = 42

In [47]: c.b
Out[47]: 42

In [49]: print(C.b.__doc__)
Hi, I'm B!

Тоді, зателефонувавши до пітонів інтерактивно help, надасть:

Help on class C in module __main__:

class C
 |  Data descriptors defined here:
 |  
 |  a
 |      Hi, I'm A!
 |  
 |  b
 |      Hi, I'm B!

що, на мою думку, повинно бути набагато тим, що ти шукаєш.

Редагувати : Зараз я усвідомлюю, що, можливо, ми можемо уникнути необхідності mypropвзагалі передавати перший аргумент , оскільки внутрішня назва не має значення. Якщо наступні дзвінки mypropможуть якось спілкуватися один з одним, він може автоматично визначитися з довгим і малоймовірним внутрішнім ім'ям атрибута. Я впевнений, що є способи цього здійснити, але я не впевнений, чи вони того варті.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.