Ітератор – це об’єкт, який у собі реалізує інтерфейс перебору чогось (іншими словами описує правило, за яким ми будемо перебирати вміст того чи іншого контейнера).
Наприклад в мене є список, який містить імена:
names = ['Костянтин', 'Ярослав', 'Остап']
for name in names:
print(name)При спробі перебрати список циклом for, відбувається взаємодія з ітератором списку, котрий цикл for отримує за рахунок неявного виклику вбудованої функції iter().
Функція iter в якості аргументу приймає об’єкт, що ітерується. Якщо в результаті її виклику буде отримано об’єкт ітератор, подальша робота проводитиметься вже з ним.
Для прикладу можна подивитись, що буде отримано, якщо передати мій список у метод iter:
print(iter(names))
# <list_iterator object at 0x000001B2C3E672B0>В результаті отримано об’єкт типу list_iterator, який інкапсулює в собі правила перебору списку.
Після отримання ітератора цикл for, за допомогою ще однієї вбудованої функції next (котрій в якості аргументу передає отриманий ітератор), робить запит наступного елемента списку до тих пір, поки не отримає у відповідь повідомлення, що елементи закінчились (помилка StopIteration).
Якщо спробувати написати аналог циклу for, за допомогою конструкції while:
names = ['Костянтин', 'Ярослав', 'Остап']
iterator = iter(names)
try:
while True:
name = next(iterator)
print(name)
except StopIteration:
print("Ітерацію завершено")Створення власних ітераторів
Створені нами класи за замовчуванням не підлягають ітерації. Для створення класу котрий можна ітерувати, потрібно реалізувати в ньому методи __iter__() та __next__():
- __iter__() – повертає сам об’єкт ітератора
- __next__() – повертає наступний елемент. Після досягнення кінця та під час наступних викликів, він повинен викликати StopIteration
class Numbers:
def __init__(self, max_number):
self.current = 1
self.max_number = max_number
def __iter__(self):
return self
def __next__(self):
if self.current <= self.max_number:
result = self.current ** 2
self.current += 1
return result
else:
raise StopIterationІмпровізований клас Numbers, в кожній ітерації повертає число в другій ступені, до тих пір, поки не досягне обмеження max_number, встановленого під час створення об’єкту.
Зверніть увагу, що в моєму випадку, об’єкт мого класу є ітератор сам по собі, тому __iter__() повертає self.
Спробую зробити ітерацію по класу Numbers циклом for:
for number in Numbers(4):
print(number)
# Output
# 1
# 4
# 9
# 16Висновок
- об’єкт що ітерується – це об’єкт який можна перебирати
- за правило перебору відповідає ітератор, а не сам об’єкт
- об’єкт що ітерується, при спробі його перебрати, повинен вміти повертати свій ітератор, щоб вже з ним тривала робота