[Python-ideas] Generators are iterators
Steven D'Aprano
steve at pearwood.info
Sun Dec 14 09:58:14 CET 2014
In an effort to try to keep this already too-long thread a bit
shorter, I'm going to trim drastically.
On Sat, Dec 13, 2014 at 09:43:02PM -0800, Andrew Barnert wrote:
> On Dec 13, 2014, at 17:17, Steven D'Aprano <steve at pearwood.info> wrote:
> > I read your reply to Chris last night, and it didn't make sense to me
> > then and it still doesn't make sense to me now :-( Hence my request for
> > a concrete example.
>
> You didn't ask for a concrete example, you provided the exact same
> answer as Chris but with different names.
My first post in this sub-thread ended with:
"So I'm not sure which mysterious object you are referring to that
doesn't have a standard name. Can you give a concrete example?"
But moving along:
> > I am still unclear as to what this mystery unnamed thing is. It's not a
> > generator function, because that is called a generator function. It's
> > not the thing you get when you call a generator function, because that
> > is called a generator or an iterator, depending on context.
>
> Again, it's the thing used by the generator instance's __next__
> method: the frame and code objects.
Aha, now the penny drops. Given a generator object, is has attributes
holding a frame object and a code object (which it shares with the
generator function that created it):
py> def gen(): yield 1
...
py> it = gen()
py> it.gi_frame
<frame object at 0xb7b8f95c>
py> it.gi_code
<code object gen at 0xb7b6e660, file "<stdin>", line 1>
py> it.gi_code is gen.__code__
True
Both have standard names: "frame object" and "code object" respectively.
> I don't know how else to explain it. Look at the members stored by the
> generator type: a frame and a code object.
That's exactly the concrete example I was looking for.
> So, going back to the original point: Generator instances are not
> different from iterators (except that it's a subtype, of course). The
> builtin generator type is likewise no different than a custom iterator
> class. The generator body is a normal function body. The only thing
> that isn't like an iterator is the frame. Which is not an important
> distinction.
Well, there are a few other differences as well. `generator` is a
concrete type, `Iterator` is an abstract type, and `iterator` can refer
to either a specific iterator type:
py> class X:
... def __getitem__(self, i): pass
...
py> iter(X())
<iterator object at 0xb7af4b0c>
or speaking more generically, to anything which obeys the iterator
protocol. More importantly, generators have abilities that other
iterators don't have: you can send data into a generator, not just get
data out of them.
> I think Chris was making a different distinction, claiming that
> generators are not an Iterator type (which they aren't, but only
> because they're _instances_ of an Iterator type, the builtin type
> generator),
I'm not sure what Chris was trying to say, but I've seen various other
people maintain that generators aren't iterators. As you say, that is
wrong:
py> from collections.abc import Iterator
py> isinstance(gen(), Iterator)
True
The *class* `generator` is an Iterator (sub-)type, but not an Iterator
itself:
py> issubclass(type(gen()), Iterator)
True
py> isinstance(type(gen()), Iterator)
False
which is no different from instances of int being numbers, but int
itself (the class) not being a number.
Thank you for helping me understand what you were trying to say.
--
Steven
More information about the Python-ideas
mailing list