How to document class attributes in Python?

94,067

Solution 1

To avoid confusion: the term property has a specific meaning in python. What you're talking about is what we call class attributes. Since they are always acted upon through their class, I find that it makes sense to document them within the class' doc string. Something like this:

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"

I think that's a lot easier on the eyes than the approach in your example. If I really wanted a copy of the attribute values to appear in the doc string, I would put them beside or below the description of each attribute.

Keep in mind that in Python, doc strings are actual members of the objects they document, not merely source code annotations. Since class attribute variables are not objects themselves but references to objects, they have no way of holding doc strings of their own. I guess you could make a case for doc strings on references, perhaps to describe "what should go here" instead of "what is actually here", but I find it easy enough to do that in the containing class doc string.

Solution 2

You cite the PEP257: Docstring Conventions, in the section What is a docstring it is stated:

String literals occurring elsewhere in Python code may also act as documentation. They are not recognized by the Python bytecode compiler and are not accessible as runtime object attributes (i.e. not assigned to __doc__), but two types of extra docstrings may be extracted by software tools:

String literals occurring immediately after a simple assignment at the top level of a module, class, or __init__ method are called "attribute docstrings".

And this is explained in more details in PEP 258: Attribute docstrings. As explains above ʇsәɹoɈ. an attribute is not an object that can own a __doc__ so they won't appear in help() or pydoc. These docstrings can only be used for generated documentation.

They are used in Sphinx with the directive autoattribute

Sphinx can use comments on a line before an assignment or a special comment following an assignment or a docstring after the definition which will be autodocumented.

Solution 3

You could abuse properties to this effect. Properties contain a getter, a setter, a deleter, and a docstring. Naively, this would get very verbose:

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

Then you will have a docstring belonging to C.x:

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

To do this for many attributes is cumbersome, but you could envision a helper function 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!

Then, calling Pythons interactive help will give:

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.

Edit: I realise now that we can perhaps avoid to need to pass the first argument to myprop at all, because the internal name doesn't matter. If subsequent calls of myprop can somehow communicate with each other, it could automatically decide upon a long and unlikely internal attribute name. I'm sure there are ways to implement this, but I'm not sure if they're worth it.

Solution 4

The other answers are very outdated. PEP-224 (available in Python 2.1!) describes how you can use docstrings for attributes. They come after the attribute, weirdly.

class C:
    "class C doc-string"

    a = 1
    "attribute C.a doc-string (1)"

    b = 2
    "attribute C.b doc-string (2)"

It also works for type annotations like this:

class C:
    "class C doc-string"

    a: int
    "attribute C.a doc-string (1)"

    b: str
    "attribute C.b doc-string (2)"

VSCode supports showing these.

Share:
94,067
intuited
Author by

intuited

// shenanigans

Updated on July 08, 2022

Comments

  • intuited
    intuited almost 2 years

    I'm writing a lightweight class whose attributes are intended to be publicly accessible, and only sometimes overridden in specific instantiations. There's no provision in the Python language for creating docstrings for class attributes, or any sort of attributes, for that matter. What is the expected and supported way, should there be one, to document these attributes? Currently I'm doing this sort of thing:

    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)
    

    This will result in the class's docstring containing the initial standard docstring section, as well as the lines added for each attribute via augmented assignment to __doc__.

    Although this style doesn't seem to be expressly forbidden in the docstring style guidelines, it's also not mentioned as an option. The advantage here is that it provides a way to document attributes alongside their definitions, while still creating a presentable class docstring, and avoiding having to write comments that reiterate the information from the docstring. I'm still kind of annoyed that I have to actually write the attributes twice; I'm considering using the string representations of the values in the docstring to at least avoid duplication of the default values.

    Is this a heinous breach of the ad hoc community conventions? Is it okay? Is there a better way? For example, it's possible to create a dictionary containing values and docstrings for the attributes and then add the contents to the class __dict__ and docstring towards the end of the class declaration; this would alleviate the need to type the attribute names and values twice. edit: this last idea is, I think, not actually possible, at least not without dynamically building the entire class from data, which seems like a really bad idea unless there's some other reason to do that.

    I'm pretty new to python and still working out the details of coding style, so unrelated critiques are also welcome.

    • Michael Scheper
      Michael Scheper over 9 years
      If you're looking for a way to document Django model attributes, this might be helpful: djangosnippets.org/snippets/2533
    • bufh
      bufh almost 9 years
      Duplicate of How to document fields and properties in Python? which hold a different solution.
    • NeilG
      NeilG over 4 years
      I don't get why this is opinion based. Python specifically documents it's acceptable conventions in PEPs. There are different Python source tools that extract properly formatted documentation. In fact Python actually has an attribute doc string mentioned in PEP 257 that isn't well known and seems hard to find that may answer the OPs question, and is supported by some source tools. This is not opinion. It's fact, and part of the language, and pretty much exactly what the OP wants.
  • intuited
    intuited about 14 years
    I guess in most cases this is fine, since the attributes —thanks for the terminology correction— are succinctly enough declared that they can just be grouped at the beginning of the class declaration without making it impractical to flip back and forth to either {read both the documentation and the default value} or {update both instances of the documentation and/or default value}.
  • intuited
    intuited about 14 years
    Also note that my example will cause the documentation for the attributes to appear in the class's docstring. I actually would prefer to put the documentation in docstrings of the attributes themselves, but this doesn't work for most builtin types.
  • intuited
    intuited almost 14 years
    Yes, my initial idea was to just declare e.g. flight_speed = 691; flight_speed.__doc__ = "blah blah". I think this is what you're mentioning in your edit. Unfortunately, this doesn't work for instantiations of (most?) builtin types (like int in that example). It does work for instantiations of user-defined types. =========== There was actually a PEP (sorry, forget the number) which proposed adding docstrings for class/module attributes, but it was declined because they couldn't figure out a way to make it clear whether the docstrings were for the preceding or following attributes.
  • Long Vu
    Long Vu almost 11 years
    jedi-vim plugin also recognize attribute docstrings.
  • jochen
    jochen almost 10 years
    I don't know when this was introduced, but Sphinx 1.2.2 seems to include attribute docstrings in the generated documentation.
  • marcz
    marcz almost 10 years
    Thank you @jochen, I update my answer.
  • n611x007
    n611x007 over 9 years
    so what if they are instance attributes? still document in the class docstring or what?
  • ʇsәɹoɈ
    ʇsәɹoɈ over 9 years
    Yep. It's pretty much the same situation with instance attributes.
  • taz
    taz over 9 years
    @intuited Was it this PEP? legacy.python.org/dev/peps/pep-0224
  • Bill
    Bill almost 6 years
    PyCharm seems to require the fuller spelling of the attributes in the docstring. I.e. Albatross.flight_speed instead of flight_speed (similar to the proposed PEP 224 linked in previous comment). This seems unnecessary to me but PyCharm complains if you don't.
  • Michał Łazowik
    Michał Łazowik over 5 years
    Please note that PEP 258 is rejected. The rejection notice states: "While this may serve as an interesting design document for the now-independent docutils, it is no longer slated for inclusion in the standard library."
  • rbaleksandar
    rbaleksandar over 2 years
    Interesting solution but unless Python does some magic under the hull creating a function and calling it just to access an attribute is unnecessary overhead. I understand that the OP is asking about documenting attributes but adding all that (especially the last one with the nested functions -_-) is way too much.
  • gerrit
    gerrit over 2 years
    @rbaleksandar You're right. I posted this more than 8 years ago, and practice shows that I never do this myself. However, I still think it shows some information about properties having docstrings, which may be of interest to some.
  • Will Da Silva
    Will Da Silva over 2 years
    PEP 224 was rejected, but this answer is still useful because numerous tools in the Python ecosystem support this way of defining attribute docstrings.
  • Timmmm
    Timmmm over 2 years
    Oh yeah I missed that. However it is just a convention and it seems that to have widespread support in spite of Guido saying he didn't like it because the strings come after the docs (which is weird tbf). E.g. here, Sphinx supports it and Pylance supports it. It's the de facto standard.
  • Will Da Silva
    Will Da Silva over 2 years
    It is also supported by mkdocstrings.
  • pabouk - Ukraine stay strong
    pabouk - Ukraine stay strong over 2 years
    VS Code's Pylance supports attribute docstrings since 2021.7.6 (released 2021-07): github.com/microsoft/pylance-release/issues/1576
  • phiresky
    phiresky over 2 years
    This behaviour is also documented in PEP 257 so it is part of the standard: "String literals occurring immediately after a simple assignment at the top level of a module, class, or `__init__`` method are called "attribute docstrings"."
  • Dumaiu
    Dumaiu over 2 years
    Putting the docstring after an attribute indeed can look odd, but I expect it prevents ambiguity between that case and the docstring written for the class or module itself.