[Python-ideas] Generator unpacking

Stephen J. Turnbull stephen at xemacs.org
Tue Feb 16 05:49:11 EST 2016


Andrew Barnert writes:
 > On Feb 15, 2016, at 19:42, Stephen J. Turnbull <stephen at xemacs.org> wrote:

 > > Are there really places where we *want* "foo(range(n))" to raise but
 > > "foo(iter(range(n)))" to do something useful?  In other words, is this
 > > really a terminology problem, rather than a problem with the design of
 > > APIs that take iterators rather than iterables?
 > 
 > Sure. Any multi-pass algorithm should raise when given an
 > iterator.

That's not my problem.  I'm not suggesting that the coercion between
iterators and non-iterators should go both directions.  If a function
that wants a Sequence is handed an iterator it should feel free to
raise.

 > In the other direction, of course, the next function requires an
 > iterator, and should and does raise when given something else.

Sure.  But next() *can't* work if the object passed doesn't maintain
internal state.  I don't think it will bother anybody if next raises
on a non-iterator, at least no more than it bothers people when
something raises on an attempt to assign to a tuple element.  My
question is "why are they iter[ator]-tools, not iter[able]-tools?"
Mostly because sequences don't need those tools very often, I guess.

 > And the slightly higher-level functions discussed in this thread
 > are the same.

Their implementations are, yes (except for the lhs ellipsis syntax,
which doesn't exist yet).

 > A function intended to consume and return the first few values in
 > an iterator while leaving the iterator holding the rest is
 > basically just a "multinext", and it would be very confusing if it
 > took a collection and left it holding all the values, including the
 > two you already used.

Greg Ewing evidently thinks that's the natural thing, so I accept that
it's not un-natural.<wink/>  And you can easily change that behavior
*without* perverse effects on space or time with iter(), at the
expense of choosing a name, and an assignment statement.

But there's an alternative interpretion of what we're looking at here
with ellipsis, at least, and that's "multipop", in which case you do
expect it to consume a Sequence, and all iterables would behave the
same in that respect.  Again, you can change that behavior with an
appropriate call to iter() (and this time you don't even need to
choose a name).

I agree that we can't get to win-win-win here, after all both
iterators and lists are optimizations of iterable, and that always
costs you something.  But I wonder if it wouldn't be possible to take
the attitude that we should do our best to optimize either list() or
iter() out of Python programs.  Since the costs of willy-nilly
applying list() to arbitrary iterables are obvious, iter() is the one
we should try to make implicit where possible.  We can't get rid of it
entirely (as with multinext vs. multipop, where either choice leaves
us wanting to call iter() for some use cases).  But maybe we could
reduce the frequency of cases where it's all too easy to forget to
call it.

 > If the current terminology were sufficiently clear and intuitive
 > that nothing needed to be done, these problems wouldn't exist.

That takes the current implementation as given, which is exactly what
I'm questioning.



More information about the Python-ideas mailing list