-1

I'm learning python online on my own, and I was reading about iterators when this question came out.

Are all iterators objects of one unique class in python, where this class has all the lists, sets, tuple methods?

martineau
  • 119,623
  • 25
  • 170
  • 301
  • No, iteration is determined by `__iter__()` and `__next__()` methods on the object. See SO question [Iteration](https://stackoverflow.com/questions/36489670/python-iter-iterator-and-generator). – Adrian Klaver Feb 06 '22 at 17:08

2 Answers2

2

Iterator is not a type. It's a protocol that different types can implement in their own way. A type is an iterator if it defines a method named __next__ that either returns some value or raises StopIteration when called. The iterator protocol is used by passing an instance of an iterator type to next, which does nothing but invoke its argument's __next__ method.

# Python equivalent to the builtin:
_next_sentinal = object()
def next(obj, default=_next_sentinal):
    try:
        return obj.__next__()
    except StopIteration:
        if default is not _next_sentinal:
            return default
        raise

An iterable is another part of the iterator protocol: a class that implements a method named __iter__ that returns a value of some type that implements __next__. The implementation of __iter__ does not have to return the same object that calls the method, or even a value of the same type as the object. (See @kaya's answer for some examples.)

The most common use of the iterator protocol is by a for loop. The code

for x in foo:
    ...

uses foo.__iter__ to get an iterator for foo, then repeatedly calls the foo iterator's __next__ method to get values to assign to x.

chepner
  • 497,756
  • 71
  • 530
  • 681
1

No, iterators are not all instances of the same class (except in the trivial sense that they are all instances of the base class object). You can verify this using the type function on many different iterators; most standard container types and other iterable types built into the language have their own iterator classes.

>>> iterables = [list(), tuple(), set(), frozenset(), dict(), dict().values(), str(), range(1)]
>>> for c in iterables:
...     print(type(c), 'has iterator type', type(iter(c)))
... 
<class 'list'> has iterator type <class 'list_iterator'>
<class 'tuple'> has iterator type <class 'tuple_iterator'>
<class 'set'> has iterator type <class 'set_iterator'>
<class 'frozenset'> has iterator type <class 'set_iterator'>
<class 'dict'> has iterator type <class 'dict_keyiterator'>
<class 'dict_values'> has iterator type <class 'dict_valueiterator'>
<class 'str'> has iterator type <class 'str_iterator'>
<class 'range'> has iterator type <class 'range_iterator'>

This works because all of the different iterator classes implement the iterator protocol, and Python uses duck typing which means Python code generally doesn't check that objects are instances of the "correct" class, instead it just uses those objects in a certain way and it works as long as those objects have the right attributes and methods to be used in that way (i.e. if they waddle like a duck and quack like a duck...).

kaya3
  • 47,440
  • 4
  • 68
  • 97