Как документировать атрибуты класса в 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)

Это приведет к тому, что строка документации класса будет содержать исходный стандартный раздел строки документации, а также строки, добавленные для каждого атрибута через расширенное присвоение __doc__.

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

Является ли это вопиющим нарушением специальных соглашений сообщества? Это нормально? Есть ли способ лучше? Например, можно создать словарь, содержащий значения и строки документации для атрибутов, а затем добавить содержимое в класс __dict__и строку документации в конце объявления класса; это избавит от необходимости вводить имена и значения атрибутов дважды. edit : эта последняя идея, я думаю, на самом деле невозможна, по крайней мере, без динамического построения всего класса из данных, что кажется действительно плохой идеей, если для этого нет другой причины.

Я новичок в Python и все еще прорабатываю детали стиля кодирования, поэтому несвязанная критика также приветствуется.

интуитивный
источник
Если вы ищете способ документировать атрибуты модели Django, это может быть полезно: djangosnippets.org/snippets/2533
Майкл Шепер
3
Дубликат Как документировать поля и свойства в Python? которые содержат другое решение.
bufh 06
1
Я не понимаю, почему это основано на мнении. Python специально документирует приемлемые соглашения в PEP. Существуют различные инструменты исходного кода Python, которые извлекают правильно отформатированную документацию. На самом деле Python действительно attribute doc stringупоминается в PEP 257, который малоизвестен и кажется трудным найти, который может ответить на вопрос OP и поддерживается некоторыми исходными инструментами. Это не мнение. Это факт, и часть языка, и в значительной степени именно то, что хочет OP.
NeilG

Ответы:

83

Во избежание путаницы: термин « свойство» имеет в Python особое значение . Вы говорите о том, что мы называем атрибутами класса . Поскольку они всегда обрабатываются через их класс, я считаю, что имеет смысл задокументировать их в строке документации класса. Что-то вроде этого:

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"

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

Имейте в виду, что в Python строки документации являются фактическими членами документируемых объектов, а не просто аннотациями исходного кода. Поскольку переменные атрибутов класса не являются объектами сами по себе, а являются ссылками на объекты, они не могут содержать собственные строки документов. Я думаю, вы могли бы привести аргументы в пользу строк документации по ссылкам, возможно, для описания «что должно быть здесь» вместо «что на самом деле здесь», но я считаю, что это достаточно просто сделать в строке документа содержащего класса.

ʇsәɹoɈ
источник
Думаю, в большинстве случаев это нормально, поскольку атрибуты - спасибо за исправление терминологии - достаточно лаконично объявлены, что их можно просто сгруппировать в начале объявления класса, не делая непрактичным переключение назад и вперед для любого {прочтите оба документацию и значение по умолчанию} или {обновить оба экземпляра документации и / или значение по умолчанию}.
интуитивно понятен
1
Также обратите внимание, что в моем примере документация по атрибутам появится в строке документации класса. На самом деле я бы предпочел поместить документацию в строки документации самих атрибутов, но это не работает для большинства встроенных типов.
интуитивно понял
Да, моя первоначальная идея заключалась в том, чтобы просто объявить, например flight_speed = 691; flight_speed.__doc__ = "blah blah". Я думаю, это то, что вы упоминаете в своей редакции . К сожалению, это не работает для экземпляров (большинства?) Встроенных типов (как intв этом примере). Он работает для экземпляров пользовательских типов. =========== На самом деле был PEP (извините, забыл номер), который предлагал добавить строки документации для атрибутов класса / модуля, но он был отклонен, потому что они не могли найти способ сделать это понятным были ли строки документации для предыдущих или последующих атрибутов.
интуитивно понятен
2
так что, если они являются атрибутами экземпляра? еще документ в класс docstring что ли?
n611x007 09
1
@intuited Это был PEP? legacy.python.org/dev/peps/pep-0224
taz
30

Вы цитируете PEP257: Docstring Conventions, в разделе Что такое docstring указано:

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

Строковые литералы, возникающие сразу после простого присваивания на верхнем уровне модуля, класса или метода __init__, называются «строками документации атрибутов».

И это объясняется более подробно в PEP 258: Строки документации атрибутов. Как объясняется выше ʇsәɹoɈ. атрибут не является объектом, которому может принадлежать __doc__, поэтому они не будут отображаться в help()pydoc. Эти строки документации можно использовать только для созданной документации.

Они используются в Sphinx с директивой autoattribute

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

Marcz
источник
1
Плагин jedi-vim также распознает строки документации атрибутов.
Long Vu
1
Я не знаю, когда это было введено, но Sphinx 1.2.2, похоже, включает строки документации атрибутов в сгенерированную документацию.
jochen
1
Спасибо @jochen, обновляю свой ответ.
Marcz 01
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

Тогда у вас будет строка документации, принадлежащая 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!

Затем вызов интерактивных Pythons 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могут каким-то образом взаимодействовать друг с другом, он может автоматически выбрать длинное и маловероятное имя внутреннего атрибута. Я уверен, что есть способы реализовать это, но я не уверен, что они того стоят.

Геррит
источник