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

Steven D'Aprano steve at pearwood.info
Mon Nov 27 10:35:50 EST 2017

On Tue, Nov 28, 2017 at 01:14:40AM +1100, Chris Angelico wrote:

> Nah, far easier:
> x, y = iter(it)
> since that'll be a no-op in the first case

Not necessarily a no-op. __iter__ might have side-effects.

Of course if you can guarantee that you ONLY have iterators, then 
there's no need to test for an iterator. But it isn't always 
appropriate to convert sequences to an iterator.

And besides, if you're going to call iter(), that's not that much 
shorter than islice() (assuming you've already imported it, of course). 
You only save five characters or so.

But the big problem here is that iterable unpacking would be 
conceptually split into "iterator unpacking" and "all other iterables 
unpacking". I think that's unnecessary complication.

> I do think islice is verbose, but the main problem is that you have to
> match the second argument to the number of assignment targets.

Yes, there is a certain amount of redundancy in having to specify the number 
of items in a slice, using either syntax:

    a, b = sequence[:2]
    a, b = islice(iterable, 2)

but it is minimal duplication, hardly the sort of thing DRY is concerned 


and there is an equally important principle that is satisfied by being 
explicit about the number of items you want. (In the face of ambiguity, 
refuse the temptation to guess.)

If you get the number wrong, you will find out immediately. And the fix 
is trivial.

In this case, there is a small but real benefit to counting the 
assignment targets and being explicit about the number of items to 
slice. Consider an extension to this "non-consuming" unpacking that 
allowed syntax like this to pass silently:

    a, b = x, y, z

That ought to be a clear error, right? I would hope you don't think that 
Python should let that through. Okay, now we put x, y, z into a list, 
then unpack the list:

    L = [x, y, z]
    a, b = L

That ought to still be an error, unless we explicity silence it. One way 
to do so is with an explicit slice:

    a, b = L[:2]

This isn't repeating yourself, it isn't really duplicated or redundant 
information. It is telling the interpreter, and more importantly the 
reader, that you want exactly two items out of a list that could contain 
any arbitrary number of items and that you are planning to bind them to 
exactly two targets.

Same goes if we use islice(iterable) instead.

Another way would be special syntax to say you want non-consuming 
unpacking, swapping out the "ambiguity" Zen for the "explicitly 
silencing errors" Zen.

So I really don't see this as anything more than, at best, a fairly 
minor piece of syntactic sugar. It doesn't really add anything to the 
language, or allow us to do anything cool we couldn't do before.


More information about the Python-ideas mailing list