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__.
Смотри еще: