Генератор — это простая функция, которая возвращает итерируемый объект, который мы можем перебирать (по одному значению за раз). Более того, у генераторной функции есть одно принципиальное отличие от обычной функции. Он имеет оператор yield вместо оператора return в обычной функции.

Чтобы построить итератор на Python, вам придется проделать большую работу. Вы должны реализовать класс с магическим методом __iter__ и __next__, отслеживать внутренние состояния и поднимать StopIteration, когда нет возвращаемых значений.

Генератор — это очень простой способ создать итератор, потому что генератор выполняет все эти шаги автоматически.

Контент-план:

  1. Создать генератор
  2. Разница между функцией генератора и обычной функцией
  3. Генератор с петлей
  4. Генераторное выражение
  5. Использование генератора
    5.1 Простота реализации
    5.2 Эффективное использование памяти
    5.3 Представление бесконечного потока
    5.4 Конвейерные генераторы
  6. "Заключение"

1. Создать генератор

Функция становится функцией-генератором, если она содержит хотя бы один оператор yield (может содержать несколько yield и даже return). Чтобы было понятно, yield и return возвращают некоторые значения из функции. Итак, вам просто нужно построить функцию хотя бы с однимyield

Основное отличие состоит в том, что оператор return полностью завершает функцию, в то время как оператор yieldприостанавливает функцию, сохраняя все ее состояния, а затем продолжает выполнение последующих вызовов.

2. Различия между генераторной функцией и обычной функцией

Давайте посмотрим на все различия между функцией-генератором и обычной функцией:

  • Генераторная функция включает один или несколько операторов yield.
  • Он возвращает объект итератора, но не выполняется немедленно.
  • Такие методы, как __iter__() и __next__(), реализуются автоматически. Это означает, что мы можем перебирать элементы, используя next().
  • Как только функция уступает, она приостанавливается, и управление передается вызывающей стороне.
  • Локальные переменные и их состояния запоминаются между последовательными вызовами.
  • Когда функция генератора завершается, StopIteration автоматически повышается при дальнейших вызовах.

Следующий пример иллюстрирует все эти моменты:

Вывод:

1 -- This is first
2 -- This is second
3 -- This is third and the last
Traceback (most recent call last):
...
StopIteration

simple_generator() — это функция-генератор с несколькими операторами yield.

Интересно отметить, что значение переменной num запоминается между каждым вызовом.

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

Чтобы начать процесс снова, вам нужно создать еще один объект-генератор, используя что-то вроде gen = simple_generator().

Последнее, на что следует обратить внимание, это то, что вы можете напрямую использовать генераторы с for циклами.

Это связано с тем, что цикл for берет итератор и перебирает его, используя функцию next(). Он автоматически заканчивается, когда поднимается StopIteration.

3. Генератор с петлей

Приведенный выше пример не имеет смысла, и я показал его только для того, чтобы вы поняли процесс работы генератора.

Обычно функции генератора реализуются с помощью цикла с подходящим условием завершения.

Итак, давайте рассмотрим следующий пример:

Вывод:

o
l
l
e
h

В коде используется функция range() для обращения полученной строки с помощью цикла for.

4. Выражение генератора

Простые генераторы можно легко создать с помощью выражений генератора. Это помогает легко строить генераторы.

Подобно лямбда-функциям, создающим анонимные функции, генераторные выражения создают анонимные генераторные функции.

Синтаксис выражения генератора аналогичен синтаксису понимание списка. Однако квадратные скобки заменяются круглыми скобками.

Основное различие между генератором списков и генератором выражений заключается в том, что списковые генераторы создают весь список, тогда как генератор > выражение создает по одному элементу за раз.

У них ленивое исполнение (производство предметов только при необходимости). Из-за этого генераторное выражение гораздо более эффективно использует память, чем эквивалентное понимание списка.

Вывод:

[100, 324, 169, 529]
<generator object <genexpr> at 0x7fafb4473bd0>

Выше мы видим, что выражение генератора не сразу дало требуемый результат. Вместо этого он вернул объект-генератор, который создает элементы только по запросу.

Вот как начать получать предметы из генератора:

Когда вы запускаете приведенный выше код, вы получаете следующий выход:

100
324
169
529
Traceback (most recent call last):
  ...
StopIteration

Выражения генератора могут использоваться в качестве аргументов функции. При таком использовании круглые скобки можно убрать.

sum(x**2 for x in list_numbers)
1122
max(x**2 for x in list_numbers)
529

5. Использование генератора

Есть несколько причин, по которым генераторы являются эффективными для реализации.

5.1. Легко реализовать

Генераторы могут быть реализованы четко и лаконично по сравнению с их аналогом класса итератора. Ниже приведен пример реализации последовательности 2 степени с использованием класса итератора.

Приведенный выше код был длинным и запутанным. Теперь давайте сделаем то же самое, используя функцию-генератор.

Поскольку генераторы автоматически отслеживают детали, реализация была лаконична и намного чище.

5.2. Эффективная память

Обычная функция для возврата последовательности создает всю последовательность в памяти перед возвратом результата. Это излишне, если количество элементов в последовательности очень велико.

Реализация генератора таких последовательностей удобна для памяти и предпочтительнее, поскольку она создает только один элемент за раз.

5.3. Представлять бесконечный поток

Генератор — отличное средство для представления бесконечного потока данных. Бесконечные потоки нельзя хранить в памяти, а поскольку генераторы производят только один элемент за раз, они могут представлять бесконечный поток данных. .

Следующая функция генератора может генерировать (теоретически) все четные числа.

5.4. Конвейерные генераторы

Можно использовать несколько генераторов для конвейерной обработки серии операций. Лучше всего это проиллюстрировать одним примером.

Допустим, у вас есть генератор, который производит числа в ряду Фибоначчи. И у нас есть еще один генератор для возведения чисел в квадрат.

Если мы хотим узнать сумму квадратов чисел в ряду Фибоначчи, мы можем сделать это следующим образом, объединяя выходные данные функций генератора.

Вывод

1120149658760

Эта конвейерная обработка эффективна и легко читается, это отличный подход.

6. Заключение

Давайте завершим это. Теперь ты знаешь:

  • Как написать и использовать генератор на Python
  • Разница между обычной функцией и функцией-генератором
  • Разница между списком и генератором
  • Преимущества генератора
  • В этом случае можно использовать генератор

P.S. Если вам понравилась эта статья, подпишитесь на меня, нажмите несколько раз Хлопки и оставьте отзыв. Удачи и эффективного программирования! Спасибо!

LinkedInТвиттер