<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <br>
    I've contributed a new PEP to humanity.  I include the RST for your
    reading pleasure below, but you can also read it online here:<br>
    <blockquote>
      <meta http-equiv="content-type" content="text/html;
        charset=ISO-8859-1">
      <a href="http://www.python.org/dev/peps/pep-0457/">http://www.python.org/dev/peps/pep-0457/</a></blockquote>
    <br>
    Discuss,<br>
    <br>
    <br>
    <i>/arry</i><br>
    <br>
    -----<br>
    <br>
    PEP: 457<br>
    Title: Syntax For Positional-Only Parameters<br>
    Version: $Revision$<br>
    Last-Modified: $Date$<br>
    Author: Larry Hastings <a class="moz-txt-link-rfc2396E" href="mailto:larry@hastings.org"><larry@hastings.org></a><br>
    Discussions-To: Python-Dev <a class="moz-txt-link-rfc2396E" href="mailto:python-dev@python.org"><python-dev@python.org></a><br>
    Status: Draft<br>
    Type: Informational<br>
    Content-Type: text/x-rst<br>
    Created: 08-Oct-2013<br>
    <br>
    <br>
    ========<br>
    Overview<br>
    ========<br>
    <br>
    This PEP proposes a syntax for positional-only parameters in Python.<br>
    Positional-only parameters are parameters without an
    externally-usable<br>
    name; when a function accepting positional-only parameters is
    called,<br>
    positional arguments are mapped to these parameters based solely on<br>
    their position.<br>
    <br>
    =========<br>
    Rationale<br>
    =========<br>
    <br>
    Python has always supported positional-only parameters.<br>
    Early versions of Python lacked the concept of specifying<br>
    parameters by name, so naturally all parameters were<br>
    positional-only.  This changed around Python 1.0, when<br>
    all parameters suddenly became positional-or-keyword.<br>
    But, even in current versions of Python, many CPython<br>
    "builtin" functions still only accept positional-only<br>
    arguments.<br>
    <br>
    Functions implemented in modern Python can accept<br>
    an arbitrary number of positional-only arguments, via the<br>
    variadic ``*args`` parameter.  However, there is no Python<br>
    syntax to specify accepting a specific number of<br>
    positional-only parameters.  Put another way, there are<br>
    many builtin functions whose signatures are simply not<br>
    expressable with Python syntax.<br>
    <br>
    This PEP proposes a backwards-compatible syntax that should<br>
    permit implementing any builtin in pure Python code.<br>
    <br>
    -----------------------------------------------------<br>
    Positional-Only Parameter Semantics In Current Python<br>
    -----------------------------------------------------<br>
    <br>
    There are many, many examples of builtins that only<br>
    accept positional-only parameters.  The resulting<br>
    semantics are easily experienced by the Python<br>
    programmer--just try calling one, specifying its<br>
    arguments by name::<br>
    <br>
        >>> pow(x=5, y=3)<br>
        Traceback (most recent call last):<br>
          File "<stdin>", line 1, in <module><br>
        TypeError: pow() takes no keyword arguments<br>
    <br>
    In addition, there are some functions with particularly<br>
    interesting semantics:<br>
    <br>
      * ``range()``, which accepts an optional parameter<br>
        to the *left* of its required parameter. [#RANGE]_<br>
    <br>
      * ``dict()``, whose mapping/iterator parameter is optional and<br>
        semantically must be positional-only.  Any externally<br>
        visible name for this parameter would occlude<br>
        that name going into the ``**kwarg`` keyword variadic<br>
        parameter dict! [#DICT]_<br>
    <br>
    Obviously one can simulate any of these in pure Python code<br>
    by accepting ``(*args, **kwargs)`` and parsing the arguments<br>
    by hand.  But this results in a disconnect between the<br>
    Python function's signature and what it actually accepts,<br>
    not to mention the work of implementing said argument parsing.<br>
    <br>
    ==========<br>
    Motivation<br>
    ==========<br>
    <br>
    This PEP does not propose we implement positional-only<br>
    parameters in Python.  The goal of this PEP is simply<br>
    to define the syntax, so that:<br>
    <br>
        * Documentation can clearly, unambiguously, and<br>
          consistently express exactly how the arguments<br>
          for a function will be interpreted.<br>
    <br>
        * The syntax is reserved for future use, in case<br>
          the community decides someday to add positional-only<br>
          parameters to the language.<br>
    <br>
        * Argument Clinic can use a variant of the syntax<br>
          as part of its input when defining<br>
          the arguments for built-in functions.<br>
    <br>
    =================================================================<br>
    The Current State Of Documentation For Positional-Only Parameters<br>
    =================================================================<br>
    <br>
    The documentation for positional-only parameters is incomplete<br>
    and inconsistent:<br>
    <br>
    * Some functions denote optional groups of positional-only arguments<br>
      by enclosing them in nested square brackets. [#BORDER]_<br>
    <br>
    * Some functions denote optional groups of positional-only arguments<br>
      by presenting multiple prototypes with varying numbers of<br>
      arguments. [#SENDFILE]_<br>
    <br>
    * Some functions use *both* of the above approaches. [#RANGE]_
    [#ADDCH]_<br>
    <br>
    One more important idea to consider: currently in the documentation<br>
    there's no way to tell whether a function takes positional-only<br>
    parameters.  ``open()`` accepts keyword arguments, ``ord()`` does<br>
    not, but there is no way of telling just by reading the<br>
    documentation that this is true.<br>
    <br>
    ====================<br>
    Syntax And Semantics<br>
    ====================<br>
    <br>
    From the "ten-thousand foot view", and ignoring ``*args`` and
    ``**kwargs``<br>
    for now, the grammar for a function definition currently looks like
    this::<br>
    <br>
        def name(positional_or_keyword_parameters, *,
    keyword_only_parameters):<br>
    <br>
    Building on that perspective, the new syntax for functions would
    look<br>
    like this::<br>
    <br>
        def name(positional_only_parameters, /,
    positional_or_keyword_parameters,<br>
                 *, keyword_only_parameters):<br>
    <br>
    All parameters before the ``/`` are positional-only.  If ``/`` is<br>
    not specified in a function signature, that function does not<br>
    accept any positional-only parameters.<br>
    <br>
    Positional-only parameters can be optional, but the mechanism is<br>
    significantly different from positional-or-keyword or keyword-only<br>
    parameters.  Positional-only parameters don't accept default<br>
    values.  Instead, positional-only parameters can be specified<br>
    in optional "groups".  Groups of parameters are surrounded by<br>
    square brackets, like so::<br>
    <br>
        def addch([y, x,] ch, [attr], /):<br>
    <br>
    Positional-only parameters that are not in an option group are<br>
    "required" positional-only parameters.  All "required"
    positional-only<br>
    parameters must be contiguous.<br>
    <br>
    Parameters in an optional group accept arguments in a group; you<br>
    must provide arguments either for all of the them or for none of
    them.<br>
    Using the example of ``addch()`` above, you could not call
    ``addch()``<br>
    in such a way that ``x`` was specified but ``y`` was not (and vice
    versa).<br>
    The mapping of positional parameters to optional groups is done<br>
    based on fitting the number of parameters to groups.  Based on the<br>
    above definition, ``addch()`` would assign arguments to parameters<br>
    in the following way:<br>
    <tt><br>
    </tt><tt>    +-------------------+------------------------------+</tt><tt><br>
    </tt><tt>    |Number of arguments|Parameter assignment          |</tt><tt><br>
    </tt><tt>    +-------------------+------------------------------+</tt><tt><br>
    </tt><tt>    |0                  |*raises an exception*         |</tt><tt><br>
    </tt><tt>    +-------------------+------------------------------+</tt><tt><br>
    </tt><tt>    |1                  |``ch``                        |</tt><tt><br>
    </tt><tt>    +-------------------+------------------------------+</tt><tt><br>
    </tt><tt>    |2                  |``ch``, ``attr``              |</tt><tt><br>
    </tt><tt>    +-------------------+------------------------------+</tt><tt><br>
    </tt><tt>    |3                  |``y``, ``x``, ``ch``          |</tt><tt><br>
    </tt><tt>    +-------------------+------------------------------+</tt><tt><br>
    </tt><tt>    |4                  |``y``, ``x``, ``ch``, ``attr``|</tt><tt><br>
    </tt><tt>    +-------------------+------------------------------+</tt><tt><br>
    </tt><tt>    |5 or more          |*raises an exception*         |</tt><tt><br>
    </tt><tt>    +-------------------+------------------------------+</tt><tt><br>
    </tt><br>
    <br>
    More semantics of positional-only parameters:<br>
    <br>
      * Although positional-only parameter technically have names,<br>
        these names are internal-only; positional-only parameters<br>
        are *never* externally addressable by name.  (Similarly<br>
        to ``*args`` and ``**kwargs``.)<br>
    <br>
      * It's possible to nest option groups.<br>
    <br>
      * If there are no required parameters, all option groups behave<br>
        as if they're to the right of the required parameter group.<br>
    <br>
      * For clarity and consistency, the comma for a parameter always<br>
        comes immediately after the parameter name.  It's a syntax error<br>
        to specify a square bracket between the name of a parameter and<br>
        the following comma.  (This is far more readable than putting<br>
        the comma outside the square bracket, particularly for nested<br>
        groups.)<br>
    <br>
      * If there are arguments after the ``/``, then you must specify<br>
        a comma after the ``/``, just as there is a comma<br>
        after the ``*`` denoting the shift to keyword-only parameters.<br>
    <br>
      * This syntax has no effect on ``*args`` or ``**kwargs``.<br>
    <br>
    It's possible to specify a function prototype where the mapping<br>
    of arguments to parameters is ambiguous.  Consider::<br>
    <br>
        def range([start,] stop, [range], /):<br>
    <br>
    Python disambiguates these situations by preferring optional groups<br>
    to the *left* of the required group.<br>
    <br>
    ======================<br>
    Additional Limitations<br>
    ======================<br>
    <br>
    Argument Clinic uses a form of this syntax for specifying<br>
    builtins.  It imposes further limitations that are<br>
    theoretically unnecessary but make the implementation<br>
    easier.  Specifically:<br>
    <br>
    * A function that has positional-only parameters currently<br>
      cannot have any other kind of parameter.  (This will<br>
      probably be relaxed slightly in the near future.)<br>
    <br>
    * Multiple option groups on either side of the required<br>
      positional-only parameters must be nested, with the<br>
      nesting getting deeper the further away the group is<br>
      from the required positional-parameter group.<br>
    <br>
      Put another way:<br>
      all the left-brackets for option groups to the<br>
      left of the required group must be specified contiguously,<br>
      and<br>
      all the right-brackets for option groups to the<br>
      right of the required group must be specified contiguously.<br>
    <br>
    <br>
    ==============================<br>
    Notes For A Future Implementor<br>
    ==============================<br>
    <br>
    If we decide to implement positional-only parameters in a future<br>
    version of Python, we'd have to do some additional work to preserve<br>
    their semantics.  The problem: how do we inform a parameter that<br>
    no value was passed in for it when the function was called?<br>
    <br>
    The obvious solution: add a new singleton constant to Python<br>
    that is passed in when a parameter is not mapped to an argument.<br>
    I propose that the value be called called ``undefined``,<br>
    and be a singleton of a special class called ``Undefined``.<br>
    If a positional-only parameter did not receive an argument<br>
    when called, its value would be set to ``undefined``.<br>
    <br>
    But this raises a further problem.  How do can we tell the<br>
    difference between "this positional-only parameter did not<br>
    receive an argument" and "the caller passed in ``undefined``<br>
    for this parameter"?<br>
    <br>
    It'd be nice to make it illegal to pass ``undefined`` in<br>
    as an argument to a function--to, say, raise an exception.<br>
    But that would slow Python down, and the "consenting adults"<br>
    rule appears applicable here.  So making it illegal should<br>
    probably be strongly discouraged but not outright prevented.<br>
    <br>
    However, it should be allowed (and encouraged) for user<br>
    functions to specify ``undefined`` as a default value for<br>
    parameters.<br>
    <br>
    ====================<br>
    Unresolved Questions<br>
    ====================<br>
    <br>
    There are three types of parameters in Python:<br>
    <br>
      1. positional-only parameters,<br>
      2. positional-or-keyword parameters, and<br>
      3. keyword-only parameters.<br>
    <br>
    Python allows functions to have both 2 and 3.  And some<br>
    builtins (e.g. range) have both 1 and 3.  Does it make<br>
    sense to have functions that have both 1 and 2?  Or<br>
    all of the above?<br>
    <br>
    <br>
    ======<br>
    Thanks<br>
    ======<br>
    <br>
    Credit for the use of '/' as the separator between positional-only
    and positional-or-keyword<br>
    parameters goes to Guido van Rossum, in a proposal from 2012.
    [#GUIDO]_<br>
    <br>
    Credit for making left option groups higher precedence goes to<br>
    Nick Coghlan. (Conversation in person at PyCon US 2013.)<br>
    <br>
    .. [#DICT]<br>
        <a class="moz-txt-link-freetext" href="http://docs.python.org/3/library/stdtypes.html#dict">http://docs.python.org/3/library/stdtypes.html#dict</a><br>
        <br>
    .. [#RANGE]<br>
        <a class="moz-txt-link-freetext" href="http://docs.python.org/3/library/functions.html#func-range">http://docs.python.org/3/library/functions.html#func-range</a><br>
        <br>
    .. [#BORDER]<br>
       
    <a class="moz-txt-link-freetext" href="http://docs.python.org/3/library/curses.html#curses.window.border">http://docs.python.org/3/library/curses.html#curses.window.border</a><br>
    <br>
    .. [#SENDFILE]<br>
        <a class="moz-txt-link-freetext" href="http://docs.python.org/3/library/os.html#os.sendfile">http://docs.python.org/3/library/os.html#os.sendfile</a><br>
    <br>
    .. [#ADDCH]<br>
        <a class="moz-txt-link-freetext" href="http://docs.python.org/3/library/curses.html#curses.window.addch">http://docs.python.org/3/library/curses.html#curses.window.addch</a><br>
    <br>
    .. [#GUIDO]<br>
       Guido van Rossum, posting to python-ideas, March 2012:<br>
      
    <a class="moz-txt-link-freetext" href="http://mail.python.org/pipermail/python-ideas/2012-March/014364.html">http://mail.python.org/pipermail/python-ideas/2012-March/014364.html</a><br>
       and<br>
      
    <a class="moz-txt-link-freetext" href="http://mail.python.org/pipermail/python-ideas/2012-March/014378.html">http://mail.python.org/pipermail/python-ideas/2012-March/014378.html</a><br>
       and<br>
      
    <a class="moz-txt-link-freetext" href="http://mail.python.org/pipermail/python-ideas/2012-March/014417.html">http://mail.python.org/pipermail/python-ideas/2012-March/014417.html</a><br>
    <br>
    =========<br>
    Copyright<br>
    =========<br>
    <br>
    This document has been placed in the public domain.<br>
  </body>
</html>