[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
with:
http://www.artima.com/intv/dry.html
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.
--
Steve
More information about the Python-ideas
mailing list