[Python-ideas] Unpack of sequences

Nick Coghlan ncoghlan at gmail.com
Thu Aug 30 03:07:56 CEST 2012

On Thu, Aug 30, 2012 at 8:18 AM, Nick Coghlan <ncoghlan at gmail.com> wrote:
> I'm personally less opposed to ideas for a new assignment statement that
> explicitly treats the lhs as a parameter definition and the rhs as an
> argument list and binds values to names accordingly, but even that would be
> a hard sell.

Expanding on this, now that I'm back at a real computer.

Argument-parameter binding is actually a fairly powerful name binding
operation, quite distinct from ordinary assignment and tuple
unpacking. It consists of two separate (often confused) components:
- the parameter specification
- the argument list

The parameter spec is what appears in the function *definition*, and
is really the main item of interest reported by the new
inspect.Signature objects in 3.3.

A parameter spec allows you to do several things:
- define the names that will be bound locally
- define default values to be assigned to those names
- provide named holders for excess positional and keyword arguments
- indicate that certain values can *only* be supplied by name, and not
by position

The argument list is what appears in a function *call*, and also has
several interesting features:
- can provide explicit positional arguments
- can provide explicit keyword arguments
- can provide an iterable of positional arguments
- can provide a mapping of additional keyword arguments

It *may* make sense to decouple this name binding operation from
function calls (and Signature.bind) and make it available as a
language primitive in the form of a statement.

However, it's *not* the same thing as an ordinary assignment statement
or tuple unpacking, and we shouldn't try to jam it implicitly into the
existing assignment statement.

There are certainly valid use cases for such a construct. One example
is support for positional only arguments. Currently, handling
positional only arguments with reasonable error messages requires
something like the following:

    def _bind_args(a=None, b=None):
        return a, b

    def f(*args):
        a, b = _bind_args(*args)

Note that the "_bind_args" function exists solely to get access to the
argument/parameter binding behaviour. Another example is unpacking
values from a dictionary, which can be done using a similar technique:

    def _bind_kwds(a=None, b=None, **other):
        return a, b, other

    def f(mapping):
        a, b, other = _bind_kwds(**mapping)

The obvious form for such a statement is "LHS OP RHS", however
syntactic ambiguity in the evaluation of both the LHS and RHS
(relative to normal assigment) would likely prevent that. As a sketch,
I'll present a notation inspired by Ruby's block parameter syntax and
emphasising the link to def statements:

    def f(*args):
        |a=None, b=None| def= *args

    def f(mapping):
        |a=None, b=None, **other| def= **mapping

This is fairly magical, but hopefully the intent is clear: the LHS is
enclosed in "|" characters to resolve the syntactic ambiguity problem
for the LHS, while a form of augmented assignment "def=" is used to
prevent assignment chaining and to resolve any syntactic ambiguity for
the RHS. It may be that there's no solution to this problem that
*doesn't* look magical.

However, if people are interested in an enhanced form of name binding
that's more powerful than the current assignment statement and tuple
unpacking, then liberating parameter binding from function calls is
the way to go. Unlike other proposals, it doesn't make the language
more complicated, because parameter binding is something people
learning Python already need to understand. Indeed, in some ways it
would make the language *simpler*, since it would allow the
explanation of parameter binding to be clearly decoupled from the
explanation of function calls and definitions.


Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia

More information about the Python-ideas mailing list