[Doc-SIG] Attribute docstrings (was: [Docutils-develop] concerns over futureof codebase)

Beni Cherniavsky cben at users.sf.net
Thu May 13 14:59:13 EDT 2004


[Moving this spin-off discussion to Doc-SIG where it belongs]

David Goodger wrote:
 > David Abrahams wrote:
 >  > David Goodger wrote:
>  > >     document = None
>  > >     """The document to write."""
>  >
>  > Whaa??  This attribute is on the class, not an instance, if I
>  > remember my Python.  It strikes me as meant to be per-instance data.
>  > What if you have several writers active at once?
> 
> Notice that these variables are being set to None.  I've updated the
> docstrings with text like "set by `write`".  They're initialized to
> bogus values in the class scope because that's one of the places where
> their docstrings will be recognized; see PEP 258.
> 
What?!?  You are initializing a value in code *only* because that's a 
precondition to the docstring being recognized?  Not having seen the 
code, I can't say whether initializing it there is healthy on other 
merits -- but it certainly sounds bad that the documentation format 
forces you to write code in a certain way.

>  > """docstrings""" used in this way are discarded by Python, and
>  > should be replaced by comments preceding the variable IMO.  I
>  > *think* that's what most people expect.
> 
> PEP 258 describes "attribute docstrings"; for full details, see
> <http://docutils.sf.net/spec/pep-0258.html#docstring-extraction-rules>,
> item 2 ("Where").
> 
Let me join the "Urf" sentiment.  I've resented this solution/syntax 
since I saw it for the following reasons:

* It provides no way to introspect these docstrings.  That's a design
   decision:

       Since attribute docstrings and additional docstrings are ignored
       by the Python byte-code compiler, no namespace pollution or
       runtime bloat will result from their use.

   but I disagree with the motivation.  I can understand the desire for
   "secondary" docstrings to limit code bloat but who said that *all*
   attribute docstrings *must* be secondary?  What if do want them at
   runtime (and I do)?  Why shouldn't I have the option?

   + Instance variables can't have the docstring attached to the value
     (because the value comes and goes, the docstring is for the slot,
     not the value).  Schemes like storing the docstring in
     `__doc_<name>__` are also ugly.  I feel that attribute docstrings
     belong at the end of the class docstring.

   + If the attribute docstring is to be appended to the class docstring,
     it should be textually marked as belonging to the attribute.  How to
     do it depends on the doc format one uses.  E.g. for reST, a
     definition list is a natural choise::

         Main class docsrting
         ...

         attr1
             Doc for attr1

         attr2
             Doc for attr2

      User control over the format is desirable.

   + It's not always convenient to document attributes one-by-one.  There
     are usaully interactions between attributes, so there might be
     better ways to structure the documentation.

     It's the same sentiment that applies to comments - frequently a
     single comment covers several statements.

* I don't like the syntax that is magically sensitive to assignments.  I
   could stand that, but being magically sensitive to assignments to
   attributes of `self` in `__init__` is way too magical to be Pythonic
   IMHO.

   I'm not sure yet whether I like the docstring before or after the
   assignment - but probably before is better.  Think of::

       foo = [
              long,
              {data: structure},
              here
             ]
       """Docstring"""

    Does it belong there?  No - for the same reasons we put comments that
    don't fit on the same line before the code: the code might be long.
    Anybody quoting the Python style for class/function docstrings as a
    precedent for putting the docstrings after the code forgets that the
    bulk of the class/function code comes after the docstring.  It
    follows only the header line (for indentation aesthetics reasons),
    which is almost guaranteed to be short.

    That's another reason the after-assignment syntax is weak.  There is
    no explicit connection of the docstring with the variable.  If
    backward-compatibility was not an issue, the following syntax would
    solve this (but only this) issue::

        attr = Value
           """Docstring"""

For all these reasons, I propose the following extremely unmagical
solution: all bare-string statements are simply concatenated together to
form this scope's docstring.  Well, not simply - at least a newline (or
two?) should be inserted because most docstrings don't end with one.

In other words, we simply allow the docstring to be split into parts
with code between them, which brings docstrings one step closer to
literate programming.

The examples from `PEP 258`__ then become::

     """g
         This is g's docstring."""
     g = 'module attribute (module-global variable)'

     class AClass:

         """c
             This is AClass.c's docstring."""
         c = 'class attribute'

         """i
             This is i's docstring."""

         def __init__(self):
             """Method __init__'s docstring."""

             self.i = 'instance attribute'

     def f(x):
         """Function f's docstring."""
         return x**2

         """a
             Function attribute f.a's docstring."""

     f.a = 1

__ http://docutils.sf.net/spec/pep-0258.html#attribute-docstrings

I had to pull the docstring for self.i out of `__init__`; this is
somewhat unfortunate.  OTOH I'm not sure the documentation of the 
attribute's *purpose* belongs with the initial assignment to it.  If 
separating the docstring from the initialization is problematic, its
separation from any other access to the attribute must be no less 
problematic...

There is no difference in this scheme between documenting a class
attribute and an instance attribute.  If important, this is better
documented in the docstring itself, because in Python there are many 
shades of it (e.g. class attributes might actually be defaults for
instance attributes).

The documentation of `f.a` is also torn away from it's assignment.
But I find it extremely hard to image a situation where there is a
special maining to an attribute of a specific function.  The meaning
of the attribute (`a`) would normally be common to all functions that 
have such an attribute.  The meaning of the attribute's value (1) should
be associated with the value (if it were a class/function, it would have
it's own docstring; number won't have docstrings in the forseable future 
;-).

-- 
Beni Cherniavsky <cben at users.sf.net>
Note: I can only read email on week-ends...



More information about the Doc-SIG mailing list