Python iterators

Итераторы в python реализуют метод __iter__ и могут реализовать метод __next__. __iter__ должен всегда возвращать self, а __next__ может возвращать некое значение.

В данном примере мы получаем бесконечный итератор, который возвращает порядковый номер итерации

>>> class Count:

...     def __iter__(self):
...         self.count = 1
...         return self

...     def __next__(self):
...         x = self.count
...         self.count += 1
...         return x

>>> c = Count()
>>> count = iter(c)
>>> print(next(count))
1
>>> print(next(count))
2

Встроенные функции next() и iter() позволяют получить итератор и извлечь значение. В цикле for..if это происходит неявно:

>>> for i in c:
>>>     if i < 10:
>>>         print(i)
1
...
9

В данном случае итератор был создан заново. Обратите внимание на условие, которое пришлось задать в цикле - без этого условия нам бы пришлось упереться в бесконечную итерацию. Чтобы решить эту логическую проблему, метод __next__ может поднимать исключение, если мы достигли граничного условия. Перепишем пример:

>>> class Count:

...     def __iter__(self):
...         self.count = 1
...         return self

...     def __next__(self):
...         x = self.count
...         if count < 10:
...             self.count += 1
...             return x
...         else:
...             raise StopIteration

>>> c = Count()
>>> for i in c:
>>>     print(i)
1
...
9

Отлично, итератор остановился там где надо, к тому же for...in самостяотельно обработал исключение. Если же мы попробуем сделать это через next(), то вот что будет:

...
8
>>> print(next(count))
9
>>> print(next(count))
Traceback (most recent call last):
...
StopIteration

Более сложные итераторы могут уметь возвращать себя в виде списка, иметь длину и т.д. Смотри подробности тут

Основное преимущество итераторов - они вычисляют значения по запросу. Таким образом не требуется вычислит ьвсю последовательность или отображение сразу, что экономит память.

Чтобы облегчить страдания программистов, в python добавлен синтаксис yield, который превращает функцию в генератор, возвращающий итератор генератора. В отличие от обычной функции с return, которая имеет одну точку входа и после возвращения значения забывает свое состояние, такой итератор будет помнить последнее состояние и при каждом вызове возобновлять работу с той точки, в которой остановился. Подробнее смотри тут: [python-datamodel]. Для асинхронных вызовов реализованы исинхронные генераторы через __aiter__ и __anext__.

Смотри еще: