[Python-Dev] PEP 457: Syntax For Positional-Only Parameters

Steven D'Aprano steve at pearwood.info
Wed Oct 9 02:15:40 CEST 2013


On Wed, Oct 09, 2013 at 01:33:26AM +0200, Larry Hastings wrote:

> This PEP proposes a syntax for positional-only parameters in Python.
> Positional-only parameters are parameters without an externally-usable
> name; when a function accepting positional-only parameters is called,
> positional arguments are mapped to these parameters based solely on
> their position.

Nicely done. A few comments follow:


> Positional-only parameters can be optional, but the mechanism is
> significantly different from positional-or-keyword or keyword-only
> parameters.  Positional-only parameters don't accept default
> values.  Instead, positional-only parameters can be specified
> in optional "groups".  Groups of parameters are surrounded by
> square brackets, like so::
> 
>     def addch([y, x,] ch, [attr], /):

I think you need to explain the motivation for this, particularly in 
light of the fact (below) that they will in fact receive a default 
value, namely the proposed "undefined" singleton.

Personally, if I have a function like this:

def mypower(x, y, [n,] /):
    if n is undefined:
        n = 1
    ...

I would much prefer to write it like this:

def mypower(x, y, [n=1,] /):
    ...


The PEP should explain why I cannot, or accept that I should be able to.


>   * For clarity and consistency, the comma for a parameter always
>     comes immediately after the parameter name.  It's a syntax error
>     to specify a square bracket between the name of a parameter and
>     the following comma.  (This is far more readable than putting
>     the comma outside the square bracket, particularly for nested
>     groups.)

I note that in your example above, you put the comma outside the square 
bracket:

def addch([y, x,] ch, [attr], /):

which seems perfectly readable to me.

I think that a much better explanation for prohibiting the comma outside 
the brackets is logical consistency: if you put the comma outside the 
brackets, and the attr is left out, you get two commas in a row and we 
don't want that.


> It's possible to specify a function prototype where the mapping
> of arguments to parameters is ambiguous.  Consider::
> 
>     def range([start,] stop, [range], /):

And you do it again, putting the comma outside of the square brackets 
:-)


> If we decide to implement positional-only parameters in a future
> version of Python, we'd have to do some additional work to preserve
> their semantics.  The problem: how do we inform a parameter that
> no value was passed in for it when the function was called?
> 
> The obvious solution: add a new singleton constant to Python
> that is passed in when a parameter is not mapped to an argument.
> I propose that the value be called called ``undefined``,
> and be a singleton of a special class called ``Undefined``.
> If a positional-only parameter did not receive an argument
> when called, its value would be set to ``undefined``.

I would much prefer Undefined and UndefinedType. That matches other 
singletons like None, NotImplemented, Ellipsis, even True and False.

What (if any) methods and attributes would Undefined have? If it doesn't 
have any, doesn't that make it functionally equivalent to None? Why not 
just use None? The PEP needs to explain why it needs to invent yet 
another singleton that quacks like None.

[Bikeshed: perhaps Missing is more appropriate than Undefined? After 
all, the parameter is defined, only the value is missing.]


> But this raises a further problem.  How do can we tell the
> difference between "this positional-only parameter did not
> receive an argument" and "the caller passed in ``undefined``
> for this parameter"?


Why treat this as a problem to be solved? If somebody wants to go to the 
trouble of writing:

addchr('c', Undefined)

instead of just:

addchr('c')

why not let them?


> It'd be nice to make it illegal to pass ``undefined`` in
> as an argument to a function--to, say, raise an exception.
> But that would slow Python down, and the "consenting adults"
> rule appears applicable here.  So making it illegal should
> probably be strongly discouraged but not outright prevented.

An argument for allowing Undefined (or None, as the case may be): 
sometimes you have a situation like this:

c = get_char()
attr = get_attr()
if attr is Undefined:  # or None
    addchr(c)
else:
    addchr(c, attr)


That sucks. But this isn't much better:

c = get_char()
attr = get_attr()
if attr is Undefined:  # or None
    t = (c,)
else:
    t = (c, attr)
addchr(*t)

Being able to pass Undefined explicitly avoids this ugliness.


> However, it should be allowed (and encouraged) for user
> functions to specify ``undefined`` as a default value for
> parameters.

Because I think this is important, I'm going to raise it again: I think 
it is important for the PEP to justify why user functions cannot specify 
arbitrary values as defaults, not just Undefined.


Thanks again for tackling this.



-- 
Steven


More information about the Python-Dev mailing list