0

I'm trying to understand the difference between iterator and generator. I read that "Every generator is an iterator, but not vice versa."

Could someone give an example of an object that IS an iterator, but IS NOT a generator?

I mean, if an object has method next (which is the definition of an iterator), we can also call it a generator, can't we?

UPD: for those who say that generator must have yield - not always. (i**2 for i in range(1,5)) doesn't have yield and is also a generator.

For those who say that iter([1,2,3]) is not a generator - why? Which definition of a generator it contradicts and where?

Timur
  • 77
  • 6
  • See also e.g. https://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do/231855#231855 – 9769953 Sep 04 '21 at 18:29
  • "I mean, if an object has method next (which is the definition of an iterator), we can also call it a generator, can't we?" **No**. You can't. Generator objects are created by generator functions (functions that use `yield`) which are a specific language construct. Just because it has a `__next__` method **does not make it a generator** – juanpa.arrivillaga Sep 04 '21 at 18:45
  • 1
    Anyway, for an example of non-generator iterators, pretty much choose any iterator created from a built-in type. So, `list_iterator = iter([1,2,3])`, or `string_iterator = iter("abcde")` – juanpa.arrivillaga Sep 04 '21 at 18:46
  • Generator objects are created by generator functions (functions that use yield) - not always. (i**2 for i in range(1,5)) is also a generator, I guess. "Anyway, for an example of non-generator iterators, pretty much choose any iterator created from a built-in type" - so, why iter([1,2,3]) is not a generator? Which definition of a generator it contradicts and where? – Timur Sep 04 '21 at 18:52
  • @Timur if you disassemble a generator expression, youlld find a generator function – juanpa.arrivillaga Sep 04 '21 at 18:56
  • As for `list_iterator`, try `import types; print(isinstance(list_iterator, types.GeneratorType))` generator is an actual *type* that implements the iterator protocol. And it isn't one because it **isn't created by a generator function**. Note, generators have *additional* methods, e.g. `.send()`. – juanpa.arrivillaga Sep 04 '21 at 18:58
  • So the difference is merely formal? Generator generates new objects that we don't know yet, whereas an iterator iterates over objects we already know (such a list). – Timur Sep 04 '21 at 19:00
  • **No**. I already explained it to you. A generator is a *specific type* created by generator functions. If you do `type(mygen)` it will give you generator . An iterator is any object with a `__next__` method. Generator objects are iterators, a specific *type of iterator* – juanpa.arrivillaga Sep 04 '21 at 19:02
  • @Timur - Prob. you can read this article - https://nvie.com/posts/iterators-vs-generators/ – Daniel Hao Sep 05 '21 at 01:35

2 Answers2

1

Could someone give an example of an object that IS an iterator, but IS NOT a generator?

Generator in Python often means a function, but can also mean an iterator created by that function. So your question is better phrased as:

Could someone give an example of an object that IS an iterator, but IS NOT a generator iterator?

Here it is:

class MyIterator:

    def __init__(self):
        self.n = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.n == 4:
            raise StopIteration
        n, self.n = self.n, self.n + 1
        return n


it = MyIterator()
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))
Cyker
  • 9,946
  • 8
  • 65
  • 93
0

"Every generator is an iterator, but not vice versa."

I don't think that's necessarily true. The Python glossary gives 3 entries that start with "generator".

Generator

This is any function with a yield statement. A generator function is not an iterator, but it does return an iterator when you call it.

def getSquares(n):
    for i in range(n):
        yield i**2

Generator iterator

This is the thing that gets returned by a generator function.

Generator expression

This is just a comprehension inside parentheses.

(i**2 for i in range(10))

Generator expressions and the return values of generator functions both give <class 'generator'> when you call type on them. However, if you define your own class with a __next__ method, its instances will, of course, have that class as their type.

luther
  • 5,195
  • 1
  • 14
  • 24
  • 1
    "Generator" can refer to either a generator function or a generator iterator, depending on context. The glossary says "Usually refers to a generator function, but may refer to a generator iterator in some contexts.", but in my experience, the iterator usage is more common. – user2357112 Sep 04 '21 at 19:20