The Python iterator interface is defined using a method called next that returns the next element of some underlying sequential series that it represents. In response to invoking next, an iterator can perform arbitrary computation in order to either retrieve or compute the next element. Calls to next make a mutating change to the iterator: they advance the position of the iterator. Hence, multiple calls to next will return sequential elements of an underlying series. Python signals that the end of an underlying series has been reached by raising a StopIteration exception during a call to next.
    The LetterIter class below iterates over an underlying series of letters from some start letter up to but not including some end letter. The instance attribute next_letter stores the next letter to be returned. The next method returns this letter and uses it to compute a new next_letter.

    1. >>> class LetterIter:
    2. """An iterator over letters of the alphabet in ASCII order."""
    3. def __init__(self, start='a', end='e'):
    4. self.next_letter = start
    5. self.end = end
    6. def __next__(self):
    7. if self.next_letter == self.end:
    8. raise StopIteration
    9. letter = self.next_letter
    10. self.next_letter = chr(ord(letter)+1)
    11. return letter

    Using this class, we can access letters in sequence using either the next method or the built-in next function, which invokes next on its argument.

    >>> letter_iter = LetterIter()
    >>> letter_iter.__next__()
    'a'
    >>> letter_iter.__next__()
    'b'
    >>> next(letter_iter)
    'c'
    >>> letter_iter.__next__()
    'd'
    >>> letter_iter.__next__()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 12, in next
    StopIteration
    

    Iterators are mutable: they track the position in some underlying sequence of values as they progress. When the end is reached, the iterator is used up. A LetterIter instance can only be iterated through once. After its next() method raises a StopIteration exception, it continues to do so from then on. Typically, an iterator is not reset; instead a new instance is created to start a new iteration.
    Iterators also allow us to represent infinite series by implementing a next method that never raises a StopIteration exception. For example, the Positives class below iterates over the infinite series of positive integers. The built-in next function in Python invokes the next method on its argument.

    >>> class Positives:
            def __init__(self):
                self.next_positive = 1;
            def __next__(self):
                result = self.next_positive
                self.next_positive += 1
                return result
    >>> p = Positives()
    >>> next(p)
    1
    >>> next(p)
    2
    >>> next(p)
    3