Пошаговое руководство по итераторам и генераторам в Python
Цикл while
и цикл for
должны активно использоваться в программировании на Python. Под капотом от нашего имени работает итератор. Сегодня вы изучите концепцию и использование итераторов и генераторов!
Итератор:
Итератор по определению предоставляет нам возможность перебирать некоторые контейнеры и скрывает конкретную логику итерации. Например, мы часто повторяем список, используя for
, а также используем пересечение набора/карты. Существует некоторая разница в низкоуровневой реализации итерации массива и карты/набора. Однако итератор скрывает эти детали от программистов, и мы можем выполнять итерацию по желанию.
Чтобы реализовать итератор, вам необходимо предоставить реализацию функций __iter__()
и __next__()
. Вам нужно предоставить оба из них: если вы предоставите только __iter()__
, ваш объект будет итерируемым, но не будет итератором. Если вы предоставите только __next()__
, он не будет ни ни итерируемым, ни итератором. Не верите? Попробуйте функцию Python isinstance()
!
В Python есть две внутренние функции, называемые iter()
и next()
. Вызов iter()
вернет итератор объекта, реализованного __iter__()
. next()
возвращает следующий шаг итератора. Пример использования: my_iterator = iter(my_object)
, за которым следует next(my_iterator).
. Когда возвращать нечего, next()
вызовет исключение StopIteration
, и итерация будет остановлена. Один интересный факт заключается в том, что если мы применяем функцию iter()
несколько раз к объекту, например. iter(iter(my_obj))
равно iter(my_obj)
.
Узнав об этом, давайте напишем собственный итератор массива. В нашем случае нам нужно не только значение, но и индекс. Например, для списка [4,5,6]
нам нужно, чтобы наш итератор печатал (0,4),(1,5),(2,6)
соответственно. Что мы делаем? Итак, мы создаем класс, который реализует как __iter__()
, так и __next__()
!См. ниже:
Генератор:
Изучение итератора, вот родной брат итератора: генератор. Ну что такое генератор? Что ж, генератор проще и гибче в реализации, чем итератор, и он возвращает нам итератор для повторения. См. пример ниже:
Здесь мы определили генератор, и каждый раз, когда мы вызываем next()
, он будет выводить следующее значение. По сути, генератор будет содержать алгоритм: пока мы знаем это значение в данный момент, мы можем правильно перейти к следующему значению. Обычно это делается с помощью ключевого слова yield
. Используя yield, мы можем добиться этого. См. генератор Фибоначчи ниже:
Каждый раз функция будет останавливаться на части yield
, а затем продолжит выполнение, начиная с последней остановки. Таким образом, общий рецепт создания генератора заключается в том, чтобы писать как обычно, но на каждом шаге, выдавая значение шага в этот момент. Как и в случае с нашим генератором Фибоначчи, каждый раз, когда мы продвигаемся вперед для вычисления следующего числа, мы получаем его значение.
Однако обычно мы не сочетаем использование next()
и генератора вместе. Мы чувствуем себя более комфортно, просто бросив наш генератор в цикл for
следующим образом:
Иногда, скажем, нам нужно 100 элементов потока из 100 миллионов чисел. Если мы попытаемся создать объект, который хранит все 100 миллионов чисел, он будет слишком массивным, как в случае с итератором. Однако, используя генератор, мы могли бы сделать это шаг за шагом и знаем, где правильно остановиться, без необходимости реализовывать функции __iter__()
и __next()__
.
В этом чтении мы представили концепцию и основное использование итератора и генератора Python. Теперь вы можете написать собственный итератор и генератор (например, создать итератор, выполняющий итерацию в обратном направлении для списка) и попробовать поиграть с ним! Этот инструмент станет удобным при реализации некоторых структур данных и алгоритмов, поскольку у вас есть полный контроль над тем, что искать в процессе итерации. Опять же, как обычно, удачного обучения и удачного кодирования!
Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter и LinkedIn. Присоединяйтесь к нашему сообществу Discord.