PEP: 3102 Title: Keyword-Only Arguments Version: $Revision$
Last-Modified: $Date$ Author: Talin <viridia@gmail.com> Status: Final
Type: Standards Track Content-Type: text/x-rst Created: 22-Apr-2006
Python-Version: 3.0 Post-History: 28-Apr-2006, May-19-2006

Abstract
========

This PEP proposes a change to the way that function arguments are
assigned to named parameter slots. In particular, it enables the
declaration of "keyword-only" arguments: arguments that can only be
supplied by keyword and which will never be automatically filled in by a
positional argument.

Rationale
=========

The current Python function-calling paradigm allows arguments to be
specified either by position or by keyword. An argument can be filled in
either explicitly by name, or implicitly by position.

There are often cases where it is desirable for a function to take a
variable number of arguments. The Python language supports this using
the 'varargs' syntax (`*name`), which specifies that any 'left over'
arguments be passed into the varargs parameter as a tuple.

One limitation on this is that currently, all of the regular argument
slots must be filled before the vararg slot can be.

This is not always desirable. One can easily envision a function which
takes a variable number of arguments, but also takes one or more
'options' in the form of keyword arguments. Currently, the only way to
do this is to define both a varargs argument, and a 'keywords' argument
(`**kwargs`), and then manually extract the desired keywords from the
dictionary.

Specification
=============

Syntactically, the proposed changes are fairly simple. The first change
is to allow regular arguments to appear after a varargs argument::

    def sortwords(*wordlist, case_sensitive=False):
        ...

This function accepts any number of positional arguments, and it also
accepts a keyword option called 'case\_sensitive'. This option will
never be filled in by a positional argument, but must be explicitly
specified by name.

Keyword-only arguments are not required to have a default value. Since
Python requires that all arguments be bound to a value, and since the
only way to bind a value to a keyword-only argument is via keyword, such
arguments are therefore 'required keyword' arguments. Such arguments
must be supplied by the caller, and they must be supplied via keyword.

The second syntactical change is to allow the argument name to be
omitted for a varargs argument. The meaning of this is to allow for
keyword-only arguments for functions that would not otherwise take a
varargs argument::

    def compare(a, b, *, key=None):
        ...

The reasoning behind this change is as follows. Imagine for a moment a
function which takes several positional arguments, as well as a keyword
argument::

    def compare(a, b, key=None):
        ...

Now, suppose you wanted to have 'key' be a keyword-only argument. Under
the above syntax, you could accomplish this by adding a varargs argument
immediately before the keyword argument::

    def compare(a, b, *ignore, key=None):
        ...

Unfortunately, the 'ignore' argument will also suck up any erroneous
positional arguments that may have been supplied by the caller. Given
that we'd prefer any unwanted arguments to raise an error, we could do
this::

    def compare(a, b, *ignore, key=None):
        if ignore:  # If ignore is not empty
            raise TypeError

As a convenient shortcut, we can simply omit the 'ignore' name, meaning
'don't allow any positional arguments beyond this point'.

(Note: After much discussion of alternative syntax proposals, the BDFL
has pronounced in favor of this 'single star' syntax for indicating the
end of positional parameters.)

Function Calling Behavior
=========================

The previous section describes the difference between the old behavior
and the new. However, it is also useful to have a description of the new
behavior that stands by itself, without reference to the previous model.
So this next section will attempt to provide such a description.

When a function is called, the input arguments are assigned to formal
parameters as follows:

-   For each formal parameter, there is a slot which will be used to
    contain the value of the argument assigned to that parameter.

-   Slots which have had values assigned to them are marked as 'filled'.
    Slots which have no value assigned to them yet are considered
    'empty'.

-   Initially, all slots are marked as empty.

-   Positional arguments are assigned first, followed by keyword
    arguments.

-   For each positional argument:

    -   Attempt to bind the argument to the first unfilled parameter
        slot. If the slot is not a vararg slot, then mark the slot as
        'filled'.

    -   If the next unfilled slot is a vararg slot, and it does not have
        a name, then it is an error.

    -   Otherwise, if the next unfilled slot is a vararg slot then all
        remaining non-keyword arguments are placed into the vararg slot.

-   For each keyword argument:

    -   If there is a parameter with the same name as the keyword, then
        the argument value is assigned to that parameter slot. However,
        if the parameter slot is already filled, then that is an error.

    -   Otherwise, if there is a 'keyword dictionary' argument, the
        argument is added to the dictionary using the keyword name as
        the dictionary key, unless there is already an entry with that
        key, in which case it is an error.

    -   Otherwise, if there is no keyword dictionary, and no matching
        named parameter, then it is an error.

-   Finally:

    -   If the vararg slot is not yet filled, assign an empty tuple as
        its value.

    -   For each remaining empty slot: if there is a default value for
        that slot, then fill the slot with the default value. If there
        is no default value, then it is an error.

In accordance with the current Python implementation, any errors
encountered will be signaled by raising `TypeError`. (If you want
something different, that's a subject for a different PEP.)

Backwards Compatibility
=======================

The function calling behavior specified in this PEP is a superset of the
existing behavior - that is, it is expected that any existing programs
will continue to work.

Copyright
=========

This document has been placed in the public domain.

.. Local Variables: mode: indented-text indent-tabs-mode: nil
sentence-end-double-space: t fill-column: 70 coding: utf-8 End:
