Итераторы
Итераторы - это объекты, которые содержат исчислимое количество значений. Другими словами, итерируя данный объект, вы перебираете его поэлементно по всем имеющимся значениям.
В Python, на техническом уровне, это реализовано следующим образом - итератором является объект, который выполняет итерационный протокол, т.е. содержит определённые методы __iter__()
и __next__()
.
Итерируемые объекты
Итерируемыми объектами в Python, например из встроенных типов данных, являются:
list
tuple
dict
set
str
(т.к. является набором символов)- и др.
Использование итератора
Получить итератор можно с помощью использования функции iter()
, передав в качестве аргумента итерируемый объект:
numbers = [5, 7, 22, 3]
myiter = iter(numbers)
print(next(myiter))
print(next(myiter))
print(next(myiter))
5
7
22
Для получения следующего элемента из итератора используется функция next()
.
Использование итератора с циклом
Цикл for
для итерируемых объектов неявно создает итератор, на который в последствии применяет функции next()
при каждой итерации. Пример:
fruits = ["apple", "banana", "orange"]
for fruit in fruits:
print(fruit)
Но можно и явно передать циклу for
заранее полученный итератор:
fruits = ["apple", "banana", "orange"]
myiter = iter(fruits)
for fruit in myiter:
print(fruit)
Создание итерируемого объекта
Как уже было сказано ранее, чтобы создать итерируемый объект, надо реализовать два специальных метода - __iter__()
и __next__()
:
__iter__()
- в данном методе могут содержаться любые инструкции, например, инструкции по инициализации некоторых переменных и т.д., но должна возвращать сам объект.__next__()
- в данном методе совершаются какие-то операции и возвращается следующий элемент из последовательности.
В качестве примера создадим объект, который будет возвращать числа от 0 с шагом 0.5:
class FloatNumbers:
def __iter__(self):
self.number = 0.0
return self
def __next__(self):
current = self.number
self.number += 0.5
return current
fnums = FloatNumbers()
myiter = iter(fnums)
print(next(fnums))
print(next(fnums))
print(next(fnums))
0.0
0.5
1.0
StopIteration
В прошлом примере был создан итерируемый объект и он отлично работает с функцией next()
, однако у него один недостаток. Если мы его передадим в цикл for
, то он будет итерировать до бесконечности. Чтобы предотвратить данную ситуацию, можно использовать встроенное исключение StopIteration
.
Добавим это исключение в метод __next__()
в прошлый пример:
class FloatNumbers:
def __iter__(self):
self.number = 0.0
return self
def __next__(self):
if self.number <= 3:
current = self.number
self.number += 0.5
return current
else:
raise StopIteration
fnums = FloatNumbers()
myiter = iter(fnums)
for n in myiter:
print(n)
0.0
0.5
1.0
1.5
2.0
2.5
3.0
Когда цикл for
доходит до значения 3.0
, вызывается исключение StopIteration
и происходит выход из цикла.