Итератор(Iterator)

Итератор(Iterator)

KarmanovichDev

Итератор - Поведенческий шаблон проектирования, предоставляющий возможность клиенту получать последовательный доступ к элементам коллекции, не вдаваясь в детали её реализации.


Идея - разделить ответственность хранения данных и знания об алгоритме их перебора. Как бы не была сложна реализация структуры данных, клиент не должен испытывать трудности при желании получить последовательный доступ к её объектам.


Коллекции, самый распространённый тип данных в языках программирования:

  • Встроенные типы данных python - list, set, dict, string, tuple, bytes, bytearray, ...
  • Коллекции не привязанные напрямую к python - стек, очередь, массив, связные списки, графы, деревья, матрицы, ...


Давайте начнём с информации о том как в python можно создать свою коллекцию данных(протокол итератора), и дать клиенту возможность получения последовательного доступа к ней.

Наверное это одна из самых коротких реализаций коллекции через класс.


Придерживайтесь этих правил при реализации протокола итератора:

  • Коллекция(iterable) должна уметь предоставить объект(iterator), который будет иметь знания о внутренней реализации коллекции.
  • Iterator должен уметь производить последовательный доступ к элементам коллекции(iterable).
  • Iterator должен обойти коллекцию один раз(полностью), после чего должен возбудить исключение StopIteration. Например, цикл for на основе этого исключения понимает, что нужно закончить попытки получения новых элементов от итератора(если исключения не будет вызвано, то внутренняя реализация for будет продолжать вызывать iterator пока не возникнет какая-либо ошибка).


Исходя из первых двух первых правил, и сути самого паттерна "Итератор" можно сделать вывод, что правильно использование итератора должно сопровождаться выносом логики итерации(если она банальна, как компромисс можно оставить), в отдельный объект, который будет хранить знания об итерации по коллекции.

Обратите внимание, несмотря на то, что логика создания итератора сложнее, чем просто передача состояния коллекции, сама коллекция, не знает о сложности этой реализации так как вызывает "фабричный статический метод" итератора.

Как менялось моё мнение об использовании итераторов в python:

  • При базовом изучении протокола итераторов python, я считал что оба метода __iter__ и __next__ должны быть у самого объекта коллекции.
  • После того как я узнал о паттерне "Итератор", то понял, что при любой не тривиальной логике, сложность итерации должна быть вынесена в другой объект. Это значило, что метод __iter__ должен быть у коллекции, а метод __next__ у итератора.
  • Сейчас же я понимаю, что эти методы просто инструмент с помощью которого я могу создавать итераторы на языке python. Ниже будет приведён пример когда оба метода будут у класса итератора.

Получается, для использования коллекции в цикле требуется, что бы переданный в цикл объект имел метод __iter__, который вернёт объект у которого есть метод __next__. Будет ли это один и тот же объект или разные на логику работы цикла не повлияет.


В конце статьи хочу показать вам устаревший способ создания итератора, который доступен и сейчас. Раньше это был единственный способ создать свой итерируемый объект. Привычный нам протокол итераторов появился только в 2001 году(python 2.2) PEP-234.

Прошу не используйте его для создания итераторов 😊




Report Page