2010-06-16 3 views
72

Я пишу легкий класс, чьи атрибуты предназначены для публичного доступа и только иногда переопределяются в конкретных экземплярах. На языке Python нет никаких условий для создания docstrings для атрибутов класса или любых атрибутов. Каков приемлемый способ, должен ли он быть, документировать эти атрибуты? В настоящее время я делаю такую ​​вещь:Как записать атрибуты класса в 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__.

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

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

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

+0

Если вы ищете способ документировать атрибуты модели Django, это может быть полезно: https://djangosnippets.org/snippets/2533/ –

+0

Дубликат [Как документировать поля и свойства в Python?] (Http : //stackoverflow.com/questions/6060813/how-to-document-fields-and-properties-in-python), которые содержат другое решение. – bufh

ответ

50

Во избежание путаницы: термин Недвижимость имеет specific meaning в python. То, о чем вы говорите, это то, что мы называем class attributes. Поскольку они всегда действуют через их класс, я нахожу, что имеет смысл документировать их внутри строки класса 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, я бы поставил их рядом или ниже описания каждого атрибута.

Edit:

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

+0

Я думаю, что в большинстве случаев это прекрасно, поскольку атрибуты -thanks для терминологической коррекции - достаточно кратко заявлены, что их можно просто сгруппировать в начале объявления класса, не делая непрактичным переворачивание назад и вперед либо {read как документация, так и значение по умолчанию} или {обновить оба экземпляра документации и/или значение по умолчанию}. – intuited

+1

Также обратите внимание, что мой пример приведет к тому, что документация для атрибутов появится в docstring класса. Я бы предпочел поставить документацию в документах самих атрибутов, но это не работает для большинства встроенных типов. – intuited

+0

Да, моя первоначальная идея состояла в том, чтобы просто объявить, например. 'flight_speed = 691; flight_speed .__ doc__ = "бла-бла". Я думаю, что это то, что вы упоминаете в своем ** **. К сожалению, это не работает для экземпляров (большинства?) Встроенных типов (например, 'int' в этом примере).Он работает для экземпляров пользовательских типов. =========== На самом деле был PEP (извините, забудьте номер), который предложил добавить docstrings для атрибутов class/module, но он был отклонен, потому что они не могли понять, как это сделать были ли docstrings для предшествующих или следующих атрибутов. – intuited

18

Вы процитировать PEP257: строка документации конвенции, в разделе What is a docstring говорится:

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

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

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

Но в настоящее время их мало используют.

Старшие Epydoc do use them и Sphinx представили его в версии 6.0 и расширили его в версии 1.1. Sphinx может использовать docstring в строке перед назначением или в специальном комментарии после назначения.

См. directive autoattribute in the Sphinx Manual и примеры атрибутов docstrings.

+0

Плагин jedi-vim также распознает атрибуты docstrings. –

+1

Я не знаю, когда это было введено, но Sphinx 1.2.2, похоже, включает атрибуты docstrings в сгенерированной документации. – jochen

+1

Спасибо @jochen, я обновляю свой ответ. – marcz

7

Вы можете злоупотреблять свойствами на этот счет. Свойства содержат геттер, сеттер, дебетер, и док-станцию ​​. Наивно, это получить будет очень многословен:

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! 

Затем, вызывая питон интерактивных help дадут:

Help on class C in module __main__: 

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

which I think should be pretty much what you're after. 

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