Итераторы являются важной основой для написания программ в функциональном стиле.
Итератор в Python - это объект, представляющий поток данных, т.е. объект, который возвращает данные по одному элементу за раз. Итератор Python должен поддерживать метод с именем __next__()
, который не принимает аргументов и всегда возвращает следующий элемент потока. Если в потоке больше нет элементов, то __next__()
должен вызвать исключение StopIteration
. Однако итераторы не обязательно должны быть конечными; вполне разумно написать итератор, генерирующий бесконечный поток данных.
Встроенная функция iter()
принимает произвольный объект и пытается вернуть итератор, который вернёт содержимое или элементы объекта, поднимая TypeError
, если объект не поддерживает итерацию. Некоторые из встроенных в Python типов данных поддерживают итерацию, наиболее распространенными из которых являются списки list
и словари dict
. Объект называется итерируемым, если для него можно получить итератор.
Можно поиграться с интерфейсом итератора вручную:
>>> L = [1, 2, 3] >>> it = iter(L) >>> it # <...iterator object at ...> # тоже самое что и next(it) >>> it.__next__() # 1 >>> next(it) # 2 >>> next(it) # 3 >>> next(it) # Traceback (most recent call last): # File "<stdin>", line 1, in <module> # StopIteration
Python ожидает итерируемые объекты в нескольких различных контекстах, наиболее важным из которых является цикл for/in
. В конструкции for X in Y
, Y
должен быть итератором или некоторым объектом, для которого iter()
может создать итератор.
Следующие два утверждения эквивалентны:
for i in iter(obj): print(i) for i in obj: print(i)
Итераторы могут быть материализованы в виде списков или кортежей с помощью функций-конструкторов list()
или tuple()
:
>>> L = [1, 2, 3] >>> iterator = iter(L) >>> t = tuple(iterator) >>> t # (1, 2, 3)
Распаковка последовательности также поддерживает итерацию: если наперед знать, что итератор вернёт N
элементов, то можно распаковать их в кортеж из N
переменных:
>>> L = [1, 2, 3] >>> iterator = iter(L) >>> a, b, c = iterator >>> a, b, c (1, 2, 3)
Встроенные функции, такие как max()
и min()
, могут принимать один аргумент - итератор и возвращать наибольший или наименьший элемент. Операторы in
и not in
также поддерживают итераторы: X in iterator
истинно, если X
найден в потоке, возвращенном итератором. Так же можно столкнутся с очевидными проблемами, если итератор бесконечен. Функции max()
, min()
и операторы in
и not in
никогда не вернут результат, если элемент X
никогда не появится в потоке.
Обратите внимание, что по итератору можно двигаться только вперед. Нет возможности получить предыдущий элемент, сбросить итератор или сделать его копию!!! Объекты-итераторы могут дополнительно предоставлять эти дополнительные возможности, но протокол итератора определяет только метод __next__()
. Следовательно, функция может потребить весь вывод итератора, и если нужно сделать что-то другое с тем же итератором, то придется создать его снова.