[Python-ideas] Unpack of sequences

Steven D'Aprano steve at pearwood.info
Thu Aug 30 17:14:07 CEST 2012


On 30/08/12 11:07, Nick Coghlan wrote:

> 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.

You're talking about the *argument list* binding operations, yes? The
stuff that happens when the function is called, not the parameter spec.


> 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.

Not only shouldn't we, but we *can't*, due to backward compatibility.

This is probably obvious to Nick, but for the benefit of anyone else
reading this who struggled as much as I did to see why we couldn't
just "upgrade" the assignment statement to work like function call
binding, here's a sketch of why we can't.

Suppose the assignment statement was upgraded. Then we could do things
like this:

a, b, c=DEFAULT, **kwargs = 1, 2, 3, d="extra"

and it would bind:

a = 1
b = 2
c = 3
kwargs = {"d": "extra"}

but DEFAULT would necessarily be unchanged. Just as if you called a
function def spam(a, b, c=DEFAULT, **kwargs).


Similarly if you did this:

a, b, c=DEFAULT = 1, 2, 3

you would expect to get the bindings:

a = 1
b = 2
c = 3

also with the default value DEFAULT unchanged.


But that second example is already legal Python, and it works
like this:


py> DEFAULT = 42
py> a, b, c=DEFAULT = 1, 2, 3
py> a, b, c
(1, 2, 3)
py> DEFAULT
(1, 2, 3)

Somebody is relying on this behaviour, and so we cannot change
assignment to work like function argument binding without breaking
backwards compatibility.

There may be other problems too, but for me, this backwards
compatibility issue convinced me that regular assignment cannot be
made to match function argument binding.

I'm not convinced that we *should* expose function argument
binding as a language primitive, but if we do, we can't use the
regular assignment statement, we would need something new.


> 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.

I think you need to explain that in further detail. Suppose we
used (making something up here) "::=" as the operator. Then e.g.:

a, b, c=DEFAULT, d=None :== 1, 2, c=3

seems unambiguous to me, provided:

1) you can't chain multiple ::= operators;

2) tuples on either side have to be delimited by parentheses,
exactly the same as is already the case for function parameter
lists and function calls, e.g.:

py> def f(a, b=1,2,3):
   File "<stdin>", line 1
     def f(a, b=1,2,3):
                  ^
SyntaxError: invalid syntax


Can you explain where the ambiguity in things like this would
lie, because I'm just not seeing it.



-- 
Steven



More information about the Python-ideas mailing list