[Python-Dev] Argument Clinic: what to do with builtins with non-standard signatures?

Serhiy Storchaka storchaka at gmail.com
Fri Jan 24 17:28:03 CET 2014


24.01.14 17:07, Larry Hastings написав(ла):
> a) Functions where there's a static Python value that behaves
>     identically to not passing in that parameter (aka "the NULL problem")
[...]
>     Possible Solutions:
>       0) Do nothing, don't convert the function.
>       1) Use that clever static value as the default.

I think #1 is reasonable solution. Internals of C function are just 
implementation details.


> b) Functions where there's no static Python value that behaves
> identically to
>     not passing in that parameter (aka "the dynamic default problem")
>
>     There are functions with parameters whose defaults are mildly dynamic,
>     responding to other parameters.
>
>     Example:
>       I forget its name, but someone recently showed me a builtin that took
>       a list as its first parameter, and its optional second parameter
>       defaulted to the length of the list.  As I recall this function didn't
>       allow negative numbers, so -1 wasn't a good fit.
>
>     Possible solutions:
>       0) Do nothing, don't convert the function.
>       1) Use a magic value as None.  Preferably of the same type as the
>          function accepts, but failing that use None.  If they pass in
>          the magic value use the previous default value.  Guido himself
>          suggested this in
>       2) Use an Argument Clinic "optional group".  This only works for
>          functions that don't support keyword arguments.  Also, I hate
>          this, because "optional groups" are not expressable in Python
>          syntax, so these functions automatically have invalid signatures.

This is list.index(self, item, start=0, stop=len(self). Vajrasky Kok 
works on this in issue20185 [1].

In this particular case we can use default stop=sys.maxsize, as in many 
other places.


> c) Functions that accept an 'int' when they mean 'boolean' (aka the
>     "ints instead of bools" problem)
[...]
>     I assert that Python has a crystal clear definition of what
>     constitutes "true" and "false".  These parameters are clearly
>     intended as booleans but they don't conform to the boolean
>     protocol.  So I suggest every instance of this is a (very mild!)
>     bug.  But changing these parameters to use "p" is a change: they'll
>     accept many more values than before.

See issue15999 [2] which 16 months waits for review.

>     Solution:
>       1) Use "bool".
>       2) Use "int", and I'll go relax Argument Clinic so they
>          can use bool values as defaults for int parameters.

I use

     int(c_default="0") = False
     int(c_default="1") = True

See also rejected issue20282 [3].


> d) Functions with behavior that deliberately defy being expressed as a
>     Python signature (aka the "untranslatable signature" problem)
>
>     Example:
>       itertools.repeat(), which behaves differently depending on whether
>       "times" is supplied as a positional or keyword argument.  (If
>       "times" is <0, and was supplied via position, the function yields
>       0 times. If "times" is <0, and was supplied via keyword, the
>       function yields infinitely-many times.)
>
>     Solution:
>       0) Do nothing, don't convert the function.
>       1) Change the signature until it is Python compatible.  This new
>          signature *must* accept a superset of the arguments accepted
>          by the existing signature.  (This is being discussed right
>          now in issue #19145.)

In this particular case this is a bug and should be fixed irrespective 
of Argument Clinic.

If we implemented this function in pure Python, we would have used the 
sentinel idiom.

_forever = object()

def repeat(value, times=_forever):
     if times is _forever:
         ...
     else:
         ...

We need an equivalent to the sentinel idiom in Argument Clinic.


There is fifth category. The default value is C constant which is not 
exposed to Python. For example in the zlib module:

zlib.decompress(data, [wbits, [bufsize]])




More information about the Python-Dev mailing list