Итератор
Итератор - это объект, который поддерживает протокол итератора, то есть имеет методы iter() и next(). Метод iter() возвращает сам итератор, а метод next() возвращает следующее значение из последовательности или вызывает исключение StopIteration, если значения закончились. Итератор можно использовать в цикле for или с функцией next().
Примеры контейнеров, которые поддерживают протокол итератора: списки (list), строки (str), словари (dict), множества (set), файлы (file) и другие.
Пример класса, который реализует протокол итератора с методами iter() и next():
Генератор
Генератор - это функция, которая использует ключевое слово yield для возврата значений из последовательности. Когда функция-генератор вызывается, она не выполняется сразу, а возвращает объект-генератор, который также является итератором. Когда метод next() объекта-генератора вызывается, функция-генератор продолжает выполнение до следующего оператора yield и возвращает значение после него. Когда функция-генератор завершается или достигает return, она вызывает исключение StopIteration.
Для создания и использования генераторов в Python с помощью функций с ключевым словом yield нужно выполнить следующие шаги:
- Определить функцию-генератор, которая использует оператор yield для возврата значений из последовательности по одному за раз. Функция может содержать несколько операторов yield или циклы с yield.
- Вызвать функцию-генератор для получения объекта-генератора, который также является объектом-итератором.
- Вызывать функцию next() на объекте-генераторе для получения следующего значения из последовательности или обработать исключение StopIteration.
Пример функции-генератора, которая возвращает бесконечную последовательность чисел:
Различия между итераторами и генераторами
- Итераторы создаются с помощью классов или функций iter() и next(), а генераторы создаются с помощью функций с yield
- Итераторы обычно реализуют конкретную логику перебора элементов контейнера или диапазона значений, а генераторы обычно реализуют ленивые вычисления на основе некоторого алгоритма
- Итераторы могут быть перезапущены с помощью метода iter(), а генераторы нельзя перезапустить после того, как они завершились
Генераторное выражение
Генераторное выражение - это более короткий способ создания объекта-генератора. Оно похоже на списковое включение, но вместо создания списка, создает объект-генератор, по которому можно итерироваться для получения значений из генератора.
Синтаксис генераторного выражения:
(<выражение> for <переменная> in <итерируемый объект> if <условие>)
Пример генераторного выражения, которое фильтрует элементы из списка по определенному условию:
numbers = [1, 2, 3, 4, 5]
# Генераторное выражение для получения четных чисел из списка even_numbers = (n for n in numbers if n % 2 == 0)
# Выводим значения из генератора с помощью функции next() print(next(even_numbers)) # 2
print(next(even_numbers)) # 4
Асинхронные итераторы и генераторы
Итераторы и генераторы имеют свои асинхронные аналоги. Асинхронные итераторы и генераторы - это специальные виды итераторов и генераторов, которые позволяют выполнять асинхронный код внутри цикла for. Они отличаются от своих синхронных версий тем, что используют ключевые слова async и await для определения и вызова асинхронных функций.
Асинхронные итераторы и генераторы применяются в ситуациях, когда нужно обрабатывать потоки данных, которые приходят нерегулярно или с задержками. Например, можно использовать асинхронный генератор для чтения данных из веб-сокета или из базы данных.
Пример асинхронного генератора, который возвращает случайные числа с разными интервалами:
Заключение
Вот краткий итог основных различий между итераторами и генераторами в Python:
- Итераторы - это объекты, имеющие методы __iter__ и __next__, которые позволяют получить следующий элемент из последовательности. Генераторы - это специальные виды итераторов, которые создаются с помощью функций с ключевым словом yield. При использовании yild, выполнение функции приостанавливается и возвращается текущее значение.
- Итераторы обычно реализуются с помощью классов, а генераторы - с помощью функций. Итераторы используют ключевое слово return для возврата значения, а генераторы - ключевое слово yield.
- Итераторы не используют никаких переменных для итерации, а генераторы используют локальные переменные и сохраняют состояние этих переменных при каждом вызове yield.
Преимущества использования генераторов для экономии памяти и упрощения кода:
- Генераторы позволяют создавать бесконечные последовательности, но мы используем память только для хранения одного значения, т.к. нам всегда известен алгоритм, по которому мы можем вычислить следующее значение.
- Генераторы позволяют отложить вычисления до тех пор, пока они не потребуются. Например, можно создать генератор для чтения большого файла построчно без загрузки всего файла в память.
- Генераторы позволяют писать более лаконичный и читаемый код с помощью генераторных выражений. Например, можно создать генератор для фильтрации элементов из списка по определенному условию с помощью одной строки кода.