Terry J. Reedy <tjre...@udel.edu> added the comment:

>From Ezio's original post: '''
If a function has optional arguments but it doesn't accept keyword arguments, 
the "func([arg1])" notation is used instead. ... The notation 
"func([arg=default])" should never be used, and "func([arg])" should be used 
only when keyword args are not accepted.
'''

In the following, I give objections to this PO (position only) rule and suggest 
an alternative ND (no default) rule: use 'name=default' when there is a default 
and '[name]' when there is not'.

The issue of whether an argument is required or optional is orthogonal to 
whether it can be passed by both position and name, only by name, or only by 
position. All combinations are possible. Optional arguments may or may not have 
a definition-time (or even run-time) default value, regardless of how passed. 
(In Python, use of *args and **kwds allows args to be optional without default.)

In the CPython stdlib, I think position-only arguments only occur with some, 
but only some, C functions. One can emulate such C functions in Python by doing 
the equivalent of what is going on with such C functions. Use a collective 
*varargs in the definition while naming the required and optional components of 
varargs in the doc as if they were the actual parameters. But I think we agree 
that emulating a limitation of C in Python is a bad idea.

So by using [] to mean both 'argument is optional' and 'function only take 
parameters by position' (or at least 'this parameter can only be passed to this 
function by position'), we are simultaneously documenting an intended and 
permanent feature of the Python function and a possibly temporary and unwanted 
side-effect of the current CPython implementation of that function. I think a 
separate PO indication might be better.

1: The PO rule goes against the effort to separate the Python language from the 
CPython implementation. With it, the doc for a function does not apply to other 
implementations that do not have the PO limitation for that function.

2: The PO rule is incomplete. It only marks an arg as position-only if it is 
optional, but not if it is required. And even if marking one arg as PO means 
that other args of the function might be, so 'watch out', there is still no 
special marking for a function with only required PO args. 

A separate sentence like "For CPython, all args must be passed by position." 
would solve both of the above problems.

3: The PO rule does not account for the possibility that an argument can be 
passed by keyword, perhaps only by keyword, but have no default. This is 
possibly in Python with **kwds in the def and recognized optional names in the 
doc. With 'name=default' and '[name]' not allowed, how should such an argument 
be documented is a signature?

4: The PO rule omits useful information on defaults from the place of 
prominence - the signature header for the entry. Sometimes the information, 
needed by some users and all implementers, gets omitted altogether. For 
example, the doc string and manual entry give the signature for str.startwith as
  str.startswith(prefix[, start[, end]])
The unmentioned defaults are None, None.

In summary, the PO rule primarily indicates, but only for optional args, 
whether the arg can be passed by keyword or not. It secondarily indicates, but 
only if it can be passed by keyword, what its default is. But if fails if the 
arg can be passed by keyword but does not have a default. It also fails, in its 
primary role, for required args.

To me, this is all mixed up. Method of passing is not related to optionality. 
What is special about optional args, regardless of how passed, is the default 
value, if it has one. The ND rule is to give exactly this information. With an 
implementation-independent signature and a separate note on passing method, 
when needed, it solves all the problems listed above. For .startswith, I would 
like to see something like
   str.startswith(prefix, start=None, end=None) ...
   CPython: pass args by position only.

---
#13355 illustrates Eric's point with a twist.
"random.triangular(low, high, mode) 
Return a random floating point number N such that low <= N <= high and with the 
specified mode between those bounds. The low and high bounds default to zero 
and one. The mode argument defaults to the midpoint between the bounds, giving 
a symmetric distribution."

The *actual* default for mode is None. The function *usually* acts if the 
default were as described. Twist 1 is that it does not actually calculate the 
midpoint, as it is not actually needed. Twist 2 is that there is currently a 
bug (easily fixed) such that triangular does not work if low>=high and mode is 
not specified, whereas it does work if the true default None is passed ;-). So 
one needs to know the real default to avoid the bug.

Of course, as I said on the issue, all defaults should be given in the 
signature (by either PO or ND rule):
"random.triangular(low=0.0, high=1.0, mode=None) ..."

And yes, +1 to documenting visible document conventions both in the documenting 
howto *and* in the docs themselves.

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue13386>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to