[Python-ideas] Proposal: "?" Documentation Operator and easy reference to argument types/defaults/docstrings

Stephen J. Turnbull turnbull.stephen.fw at u.tsukuba.ac.jp
Fri Apr 26 05:18:30 EDT 2019


David Mertz writes:

 > Why not just this in existing Python:
 > 
 >     def func_1(

If I understand the OP's POV, one reason is that the following
comments are not available to help() in existing Python.  (From the
Picky-Picky-Picky Dept: It's a syntax error since a and b are not
separated by the comma in the comment!)  Did you mean "use existing
Python syntax and have future interpreters use the comments"?

 >             a: int = 1 # 'Something about param a',
 >             b: float = 2.5 # 'Something else about param b',
 >             ) -> float:
 >         """Something about func_1
 > 
 >         a and b interact in this interesting way.

More from the Picky-Picky-Picky Dept: Again from the OP's POV, the
following two lines belong in the signature I believe.  I tend to
differ, because they are (in principle) checkable, though only at
runtime.  See (2) below.

 >         a should be in range 0 < a < 125
 >         floor(b) should be a prime number

What I would rather see is

(1) Comment syntax "inside" (fvo "inside" including any comment after
    the colon but before docstring or other code) the signature is
    interpreted as parameter documentation strings, which are
    available to help().  This is backward compatible; older Pythons
    will ignore them.  The only problem would be if programs
    introspect their own docstrings and change behavior based on the 
    result, which is so perverse that I'm happy to go with "if you do
    that, you deserve to suffer."

(2) asserts involving parameters lexically are available to help().
    I equate "assert" to your "should" since both have indeterminate
    semantics if violated at runtime.  Of course this is subject to
    the usual caveats about use of assert to check user input at
    runtime!  Perhaps argument-checking code not marked by an assert
    could be marked in some other way?

So, after

    def featherfall(      # not for use with parrots, dead or alive
        a: int = 1,       # number of swallows in flock
        b: float = 2.5    # mean feather density of swallows
        ) -> float:       # volume of feathers released when a flock
                          # of swallows is stooped on by an F-35

        """
        The interaction of flock size and feather density may not be
        fully captured by multiplication.  Also reports F-35's
        friend-or-foe ID to NORAD.
        Unimplemented: generalization to differential feather
        densities between African and European swallows and
        multiple disjoint flocks.
        Implemented for DoD contract #DEADBEEF666.
        """

        assert 0 < a < 255           # not essential that these are
        assert prime(floor(b))       # the first code in the function
        c = a & floor(b)
        assert c != 0                # NOT documented in help()

        return a*b

help() could produce

        featherfall (not for use with parrots, dead or alive)

        Parameters:
        a, an int, represents number of swallows in flock.
        Defaults to 1 and satisfies 0 < a < 255.
        b, a float, represents mean feather density of swallows.
        Defaults to 2.5 and satisfies prime(floor(b)).

        Returns:
        A float, whose value is the volume of feathers released when a
        flock of swallows is stooped on by an F-35.

        The interaction of flock size and feather density may not be
        fully captured by multiplication.  Also reports F-35's
        friend-or-foe ID to NORAD.
        Unimplemented: generalization to differential feather
        densities between African and European swallows and
        multiple disjoint flocks.
        Implemented for DoD contract #DEADBEEF666.

I'm not sure what to do with asserts involving multiple parameters.
They could be repeated for each parameter involved, or put in a
separate set of "Satisfies" conditions at the bottom of the
Parameters: section.

The main objection I see to the whole idea (and it may kill it) is
that the comments aren't syntactically code, so that the formatting
matters.  (I'm also unsure whether they fall afoul of Guido's "No
pragmas" dictat.)  You could satisfy "must be code" with

    def featherfall(
        a: int = (1, 'number of swallows in flock')[0],
        b: float = (2.5, 'mean feather density of swallows')[0]
        ) -> float:       # volume of feathers released when a flock
                          # of swallows is stooped on by an F-35

but I think that falls into the "too ugly to live" category.  NB: Any
comment on the signature would be attached as documentation to the
return value.  It would also be possible to attach each comment in the
signature to the most recently read component (function name,
parameter, return type) so that

    def featherfall(      # not for use with parrots, dead or alive
        a: int = 1, b: float = 2.5    # mean feather density of swallows
        ) -> float:

would attach documentation to the function name and the parameter b,
but not to the parameter a and the return type.  This is well-defined,
but maybe too pedantic to survive?

The help text is of course infinitely bikesheddable.  I suppose some
people would prefer more backward compatibility.  Ie, instead of the
function name with comment as header, the header would be the
signature.  What that would look like is left as an exercise for the
reader, but I would expect that the signature in the help output
doesn't include the comment data.

Personally, I don't really understand the "fails DRY" argument.  If
it's in the signature already, don't put it in the docstring.  (If the
project uses stub files, I guess this would require the ordinary
compiler to look for them which might or might not be an acceptable
tradeoff if it doesn't do that already.)

Steve



More information about the Python-ideas mailing list