Итератор — это поведенческий паттерн, позволяющий последовательно обходить сложную коллекцию, без раскрытия деталей её реализации.
Благодаря Итератору, клиент может обходить разные коллекции одним и тем же способом, используя единый интерфейс итераторов.
Сложность:
Популярность:
Применимость: Паттерн можно часто встретить в Python-коде, особенно в программах, работающих с разными типами коллекций, и где требуется обход разных сущностей.
Признаки применения паттерна: Итератор легко определить по методам навигации (например, получения следующего/предыдущего элемента и т. д.). Код использующий итератор зачастую вообще не имеет ссылок на коллекцию, с которой работает итератор. Итератор либо принимает коллекцию в параметрах конструктора при создании, либо возвращается самой коллекцией.
Концептуальный пример
Этот пример показывает структуру паттерна Итератор , а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
main.py: Пример структуры паттерна
from __future__ import annotations
from collections.abc import Iterable, Iterator
from typing import Any
"""
Для создания итератора в Python есть два абстрактных класса из встроенного
модуля collections - Iterable, Iterator. Нужно реализовать метод __iter__() в
итерируемом объекте (списке), а метод __next__() в итераторе.
"""
class AlphabeticalOrderIterator(Iterator):
"""
Конкретные Итераторы реализуют различные алгоритмы обхода. Эти классы
постоянно хранят текущее положение обхода.
"""
"""
Атрибут _position хранит текущее положение обхода. У итератора может быть
множество других полей для хранения состояния итерации, особенно когда он
должен работать с определённым типом коллекции.
"""
_position: int = None
"""
Этот атрибут указывает направление обхода.
"""
_reverse: bool = False
def __init__(self, collection: WordsCollection, reverse: bool = False) -> None:
self._collection = collection
self._reverse = reverse
self._position = -1 if reverse else 0
def __next__(self) -> Any:
"""
Метод __next __() должен вернуть следующий элемент в последовательности.
При достижении конца коллекции и в последующих вызовах должно вызываться
исключение StopIteration.
"""
try:
value = self._collection[self._position]
self._position += -1 if self._reverse else 1
except IndexError:
raise StopIteration()
return value
class WordsCollection(Iterable):
"""
Конкретные Коллекции предоставляют один или несколько методов для получения
новых экземпляров итератора, совместимых с классом коллекции.
"""
def __init__(self, collection: list[Any] | None = None) -> None:
self._collection = collection or []
def __getitem__(self, index: int) -> Any:
return self._collection[index]
def __iter__(self) -> AlphabeticalOrderIterator:
"""
Метод __iter__() возвращает объект итератора, по умолчанию мы возвращаем
итератор с сортировкой по возрастанию.
"""
return AlphabeticalOrderIterator(self)
def get_reverse_iterator(self) -> AlphabeticalOrderIterator:
return AlphabeticalOrderIterator(self, True)
def add_item(self, item: Any) -> None:
self._collection.append(item)
if __name__ == "__main__":
# Клиентский код может знать или не знать о Конкретном Итераторе или классах
# Коллекций, в зависимости от уровня косвенности, который вы хотите
# сохранить в своей программе.
collection = WordsCollection()
collection.add_item("First")
collection.add_item("Second")
collection.add_item("Third")
print("Straight traversal:")
print("\n".join(collection))
print("")
print("Reverse traversal:")
print("\n".join(collection.get_reverse_iterator()), end="")
Output.txt: Результат выполнения
Straight traversal:
First
Second
Third
Reverse traversal:
Third
Second
First