Что такое итераторы?
Итератор в Python относится к объекту, по которому мы можем выполнять итерацию. Итератор состоит из счетных значений, и эти значения можно просматривать одно за другим.
Итератор просто реализует протокол итератора Python. Протокол итератора
- это класс Python, который имеет два специальных метода, а именно
__iter__()
и__next__()
. С помощью этих двух методов итератор может вычислить следующее значение в итерации.
С итераторами нам легко работать с последовательностями элементов в Python. Нам не нужно выделять вычислительные ресурсы всем элементам в последовательности, мы выполняем итерацию по одному элементу за раз, что помогает нам сэкономить место в памяти.
В этой статье мы изучим, как работать с итераторами в Python.
Итерируемые объекты в Python
Итерируемый объект - это объект, способный возвращать итератор.
Итерируемый объект может представлять как конечные, так и бесконечные
источники данных. Итерация прямо или косвенно реализует два метода:
__iter__()
и __next__()
. Метод __iter__()
возвращает
объект-итератор, а метод __next__()
помогает нам перемещаться по
элементам в итеративном объекте.
Примеры итерируемых объектов в Python включают списки, словари, кортежи и наборы.
Создание итератора
В Python мы создаем итератор, реализуя для __iter__()
и __next__()
.
Рассмотрим следующий пример:
class IterationExample:
def __iter__(self):
self.x = 0
return self
def __next__(self):
y = self.x
self.x += 1
return y
classinstance = IterationExample()
element = iter(classinstance)
Мы создали итератор с именем element
который печатает числа от 0 до N.
Сначала мы создали экземпляр класса и дали ему имя classinstance
.
Затем мы вызвали iter()
и передали имя экземпляра класса в качестве
параметра. Это создает объект-итератор.
Давайте теперь обсудим, как использовать итератор для фактического перебора элементов.
Итератор
Метод next()
помогает нам перебирать элементы итератора.
Продемонстрируем это на примере, приведенном выше:
class IterationExample:
def __iter__(self):
self.x = 0
return self
def __next__(self):
y = self.x
self.x += 1
return y
classinstance = IterationExample()
element = iter(classinstance)
print(next(element))
print(next(element))
print(next(element))
print(next(element))
print(next(element))
print(next(element))
print(next(element))
print(next(element))
print(next(element))
print(next(element))
Выход
0
1
2
3
4
5
6
7
8
9
В приведенном выше скрипте мы вызвали метод next()
и передали ему имя
элемента итератора в качестве параметра. Каждый раз, когда мы это
делаем, итератор переходит к следующему элементу в последовательности.
Вот еще один пример:
# create a list
list1 = [0, 5, 10, 15]
# create an iterator
element = iter(list1)
## use next() to traverse/iterate through the list elements
# prints first element, 0
print(next(element))
# prints second element, 5
print(next(element))
## next(element) is similar to element.__next__()
# prints third element, 10
print(element.__next__())
# prints fourth element, 15
print(element.__next__())
Выход
0
5
10
15
В приведенном выше сценарии мы создали список с именем list1
, который
содержит 4 целых числа. Создан итератор с именем element
. Метод
next()
помог нам перебрать элементы списка.
Итерация с помощью цикла "for"
Цикл for
помогает нам перебирать любой объект, способный возвращать
итератор. Например:
# create a list
list1 = [0, 5, 10, 15]
# create an iterator
element = iter(list1)
# iterate with a for loop
for x in element:
print(x)
Выход
0
5
10
15
В приведенном выше коде мы создали переменную с именем x
, которая
используется для перебора element
итератора через цикл for
Бесконечные итераторы
Бесконечный итератор - это итератор с бесконечным числом итераций. Мы должны быть особенно осторожны при работе с бесконечными итераторами. Рассмотрим следующий пример:
class IterationExample:
def __iter__(self):
self.x = 0
return self
def __next__(self):
y = self.x
self.x += 1
return y
classinstance = IterationExample()
element = iter(classinstance)
for x in element:
print(x)
Приведенный выше код будет работать вечно. Чтобы остановить это, вам придется вмешаться вручную. Вот еще один пример, демонстрирующий, как создать бесконечный итератор в Python:
class Infinite:
# Print all even numbers
def __iter__(self):
self.x = 0
return self
def __next__(self):
x = self.x
self.x += 2
return x
Код должен возвращать все четные числа, начиная с 0. Мы можем запустить код, как показано ниже:
>>> y = iter(Infinite())
>>> next(y)
0
>>> next(y)
2
>>> next(y)
4
>>> next(y)
6
>>> next(y)
8
>>> next(y)
10
>>>
И эта цепочка может продолжаться вечно. Это показывает, что с бесконечным итератором мы можем иметь бесконечное количество элементов без необходимости хранить их все в памяти.
В следующем разделе мы увидим, как мы можем реализовать механизм выхода из таких бесконечных итераторов.
Остановка итерации
В предыдущем разделе мы увидели, как создать бесконечный итератор в Python. Однако итераторы обычно не предназначены для бесконечных итераций в Python. Всегда удобно реализовать условие завершения.
Мы можем остановить выполнение итератора навсегда с StopIteration
оператора StopIteration. Нам нужно только добавить условие завершения в
метод __next__()
которое вызовет ошибку при достижении указанного
количества итераций. Вот пример:
class StoppingIteration:
def __iter__(self):
self.x = 1
return self
def __next__(self):
if self.x <= 5:
y = self.x
self.x += 1
return y
else:
raise StopIteration
classinstance = StoppingIteration()
element = iter(classinstance)
for a in element:
print(a)
Выход
1
2
3
4
5
Выполнение останавливается после 5 итераций. Это из-за self.x <= 5:
добавленного в метод __next__()
. Если итератор вызывается после
достижения 5, он StopIteration
событие StopIteration. Рассмотрим
пример, приведенный ниже:
class StoppingIteration:
def __init__(self, max = 0):
self.max = max
def __iter__(self):
self.x = 1
return self
def __next__(self):
if self.x <= self.max:
val = 3 ** self.x
self.x += 1
return val
else:
raise StopIteration
Давайте создадим итератор, а затем переберем его:
>>> y = StoppingIteration(3)
>>> z = iter(y)
>>> next(z)
3
>>> next(z)
9
>>> next(z)
27
>>> next(z)
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
next(z)
File "C:\Users\admin\iteration.py", line 17, in __next__
raise StopIteration
StopIteration
>>>
Условие завершения было реализовано в следующем разделе нашего кода:
if self.x <= self.max:
val = 3 ** self.x
Мы передали итератору значение 3, что означает, что итератор не должен выполнять итерацию более 27, то есть 3 ^ 3.
Заключение
Итераторы чрезвычайно полезны, особенно если вам нужно перебрать большую последовательность элементов. Итераторы позволяют выполнять итерацию по последовательности элементов по одному без необходимости загружать все элементы в память сразу.
В этой статье мы увидели, как создавать итераторы в Python и как перебирать элементы в итераторе. Мы также увидели, как создать бесконечный итератор и как добавить условие завершения к бесконечному итератору.