Iterator
Паттерн обхода: перебрать элементы коллекции, не зная и не раскрывая, как она устроена внутри.
Iterator предоставляет способ последовательного доступа к элементам коллекции, не раскрывая её внутреннее представление.
Какую задачу решает
Список, дерево и связный список устроены по-разному, но перебирать их хочется одинаково: for x in collection. Iterator отделяет обход от хранения: коллекция отдаёт итератор, который знает, как двигаться по ней, а клиент работает с единым протоколом. В Python этот паттерн встроен в язык.
Идея и реализация
Протокол итератора в Python — методы __iter__ (вернуть итератор) и __next__ (вернуть следующий элемент или бросить StopIteration). Сделаем коллекцию, обходящую элементы в обратном порядке.
class Reversed:
def __init__(self, data):
self._data = data
def __iter__(self):
self._i = len(self._data)
return self
def __next__(self):
if self._i == 0:
raise StopIteration
self._i -= 1
return self._data[self._i]
for item in Reversed(["a", "b", "c"]):
print(item)
Вывод:
c b a
Цикл for сам вызывает __iter__, затем многократно __next__, пока не поймает StopIteration. Клиент не знает, что внутри список и что обход идёт с конца — он просто перебирает. Любую структуру (дерево, граф) можно сделать перебираемой так же.
Питоничный способ: генераторы
В Python почти всегда вместо ручных __next__ пишут генератор с yield — это и есть итератор, созданный компактно.
def countdown(n):
while n > 0:
yield n # лениво отдаём значения по одному
n -= 1
print(list(countdown(3)))
print(sum(countdown(5)))
Вывод:
[3, 2, 1] 15
Генератор ленив: значения вычисляются по мере запроса, что позволяет работать с бесконечными или огромными последовательностями без загрузки всего в память.
Где встречается
Везде в Python: for, распаковка, map/filter, itertools, чтение файла построчно. В других языках — Iterator/IEnumerable, обход коллекций, потоки данных, пагинация API (следующий итератор подгружает следующую страницу).
Итог
- Iterator отделяет обход от хранения, давая единый протокол перебора.
- В Python — это
__iter__/__next__иStopIteration. - Генераторы с
yield— самый компактный способ создать итератор.