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