__next__ and StopIteration

Ian Kelly ian.g.kelly at gmail.com
Mon Feb 9 18:56:36 EST 2015


On Mon, Feb 9, 2015 at 4:30 PM, Steven D'Aprano
<steve+comp.lang.python at pearwood.info> wrote:
> The way you write iterators is like this:
>
>
> Method 1 (the hard way):
>
> - Give your class an __iter__ method which simply returns self:
>
>     def __iter__(self):
>         return self
>
> - Give your class a __next__ method (`next` in Python 2) which *returns* a
> value. You will need to track which value to return yourself. It must raise
> StopIteration when there are no more values to return. Don't use yield.
>
>     def __next__(self):
>         value = self.value
>         if value is None:
>             raise StopIteration
>         self.value = self.calculate_the_next_value()
>         return value
>
> Your class is itself an iterator.

This is an anti-pattern, so don't even suggest it. Iterables should
never be their own iterators. Otherwise, your iterable can only be
iterated over once!

The proper version of the "hard way" is:

1) The __iter__ method of the iterable constructs a new iterator
instance and returns it.

2) The __iter__ method of the *iterator* simply returns itself.

3) The __next__ method of the iterator tracks the current value and
returns the next value. Note that the iterator should never store the
iterable's data internally, unless the iterable is immutable and the
calculation is trivial (e.g. a range object). Instead, it should
determine the next value by referring to its source iterable.



More information about the Python-list mailing list