[Python-Dev] Half-baked proposal: * (and **?) in assignments

Delaney, Timothy tdelaney@avaya.com
Sun, 24 Nov 2002 12:27:06 +1100


> From: Brett Cannon [mailto:bac@OCF.Berkeley.EDU]
> 
> But is it that big of a deal to just take the [1:] index of something
> instead of using this suggested addition?

Actually, it can be.

    a = func()
    b, c = a[:1], a[1:]

vs

    b, *c = func()

The first version leads to namespace pollution, which you cannot safely
ignore. The two options are:

    a = func()
    b, c = a[:1], a[1:]
    del a

in which case you may at times fail to del a (probably not a big issue if an
exception has been thrown ... unless a is global, but we don't do that ;)

    b = func()
    b, c = b[:1], b[1:]

which again may potentially screw up.

Additionally, the

    b, *c = func()

version will work with any iterator on the RHS, unlike the slicing version.
I see two options for this:

1. b is assigned the first value, c is assigned a tuple of the remaining
values

2. b is assigned the first value, c is assigned the iterator.

Hmm - on further thought, #2 may be the way to go - the value with a * is
always assigned the result of calling iter() on the remainder.

That would also produce a distinction between

    a = t    # a is assigned a tuple
    *a = t   # a is assigned a tuple iterator

In that case,

    a, *b, c = t

would have to perform the following shennanigans:

1. Extract all the values.
2. Assigned the first value to a, and the last value to c.
3. Create a tuple out of the rest, get its iterator and assign that to b.

In the common case however of:

    a, b, *c = t

that could be reduced to:

1. Get the iterator.
2. Assign the result of .next() to a.
3. Assign the result of .next() to b.
4. Assign the iterator to c.

i.e. if the asterisk is attached to any but the last name of the LHS, there
better not be an infinitly-long iterable in the RHS ;)

Something further to think about.

Tim Delaney