[Python-ideas] How assignment should work with generators?

Chris Angelico rosuav at gmail.com
Mon Nov 27 06:02:53 EST 2017


On Mon, Nov 27, 2017 at 9:45 PM, Kirill Balunov <kirillbalunov at gmail.com> wrote:
> 2017-11-27 12:40 GMT+03:00 Chris Angelico <rosuav at gmail.com>:
>> If you use "x, y, *z = gen1()", you'll trigger all the prints and
>> completely consume the generator. With gen2(), you'll get an infinite
>> loop. Both of those are semantically different from the islice
>> behaviour, which would consume only that part that you're looking for.
>
>
> The idea is not to consume generator completely, but to get enough values to
> bind to x and y. It should be equivalent to islice(iter, 2), and perceiveв
> as "bind x, y, where you don't need values for z at all".

In terms of language proposals, you can't just say "don't need values
for"; the semantics have to be EITHER "consume and discard" OR "don't
consume". We already have a perfectly good way of spelling "consume
and discard":

x, y, _ = iter

following the convention that a single underscore means "don't really
care" (eg "for _ in range(3)"). So this proposal is about not
consuming an iterator.

>> x, y, * = iter # unpack into nothing
>
> Maybe, I like it.
>
>> x, y, ... = iter # assigning to Ellipsis
>> x, y, *... = iter # as above but clearly sequencing
>
>
> Yes, it is nice to see Ellipsis as zero-length deques (or throw away
> container), it can be used also in the middle of list of targets. What I
> don't like about last three examples, that they imply by their form to be
> some kind of iteration which must completely consume the generator, which is
> opposite to the proposed idea. Moreover, this will not work with infinite
> generators, falling into infinite loop.

Since this has to be about non-consumption of the generator/iterator,
Ellipsis cannot be a zero-length deque. Thus this syntax would have to
be restricted to the *last* entry, and it then means "don't check for
more elements".

The assignment "x, y = it" is roughly equivalent to:

try:
    _iter = iter(it)
    x = next(_iter)
    y = next(_iter)
except StopIteration:
    raise ValueError
else:
    try:
        next(_iter)
    except StopIteration:
        pass # good, we got the right number of elements
    else:
        raise ValueError

The proposed semantics, if I understand you correctly, are:

try:
    _iter = iter(it)
    x = next(_iter)
    y = next(_iter)
except StopIteration:
    raise ValueError
# no "else" clause, we're done here

And I think this would be a good thing to be able to spell
conveniently. The only questions are: what spelling is the best, and
is it sufficiently useful to justify the syntax?

>> And there are a few others too. Every one of them has its downsides,
>> none is perfect. (Personally, I think one of the Ellipsis options is
>> likely the best, or perhaps the least-bad.) Want to spearhead the PEP?
>
> To be honest, I'm quite new to the entire ecosystem of Python. Therefore,
> someone can perceive this as an ordinary attempt by a novice to change
> everything that is bad in his opinion. In addition, it seems to me that
> these changes, if approved, can not be made earlier than Python3.8, so I
> would like to get some feedback first. Nevertheless these words should not
> be taken as a renouncement, I would be happy and very interested in writing
> PEP and implementing it. But not to get stuck I need some support and
> guidelines from interested dev.

Yes; now that we're into alphas for Python 3.7, it's not going to land
until 3.8. That's fine.

The PEP process is basically a way of gathering all the arguments
for-and-against into a single, coherent document, rather than having
them scattered all over the python-ideas email archive. The PEP author
has the final say on what is the thrust of the proposal, and then
Guido (or his delegate) will decide to accept or reject the PEP. If
it's accepted, the change will be made; if it's not, the PEP remains
in the repository as a permanent record of the proposal. That way, the
*next* person to come along and suggest something can pick up from
where this discussion left off, rather than starting fresh.

Start by perusing PEP 1, and the template in PEP 12:

https://www.python.org/dev/peps/pep-0001/
https://www.python.org/dev/peps/pep-0012/

The PEP editors (myself included) are here to help you; don't hesitate
to reach out with questions.

ChrisA


More information about the Python-ideas mailing list