Для написания функций-генераторов вы должны использовать ключевое слово yield вместо return. Функции, содержащие инструкцию yield, компилируются генераторы. При вызове такой функции она возвращает объект генератора, поддерживающий интерфейс итераций с помощью автоматически созданного метода __next__, позволяющего продолжить выполнение.
В примере выше мы видим, что в переменной s после вызова функции genf() содержится именно генератор. Из предыдущего занятия мы знаем, что генератор - это итератор, элементы которого можно итерировать(обходить поэлементно) только один раз. К итераторам можно вызывать функцию next() и при каждом новом вызове функция-генератор будем генерировать новый элемент из своей коллекции.
В отличие от обычных функций, которые возвращают значение и завершают работу, функции-генераторы автоматически приостанавливают(замораживают) и возобновляют свое выполнение, при этом сохраняя информацию, необходимую для генерации следующих значений.
При заморозке Функции-генераторы автоматически сохраняют информацию о своем состоянии и в том числе все локальные переменные, которые становятся доступны сразу же после того, как функция возобновляет свою работу.
Главное отличие функций-генераторов от обычных функций состоит в том, что функция-генератор передает по одному значению, а не возвращает целиком сразу весь результат и завершает работу. Инструкция yield приостанавливает работу функции и передает значение вызывающей программе, при этом сохраняется информация о состоянии функции, необходимая, чтобы потом вновь возобновить работу с места остановки. Когда функция-генератор возобновляет работу, ее выполнение продолжается с первой инструкции, следующей за инструкцией yield.
В примере ниже обычная функция fact(n) возвращает при помощи return список факториалов от 1 до n. При этом для хранения этого списка выделяется память.
Но мы можем переписать этот код и сделать функцию-генератор. Она будет предоставлять нам значения одно значение по требованию и при этом помнить накопленный ранее результат. При таком варианте написания мы съэкономим память, отказавшись от использования списка.