Генераторы¶
Генераторы представляют собой итерируемый тип, такой как списки или кортежи.
 В отличие от списков им нельзя присваивать произвольные индексы, но они поддерживают циклы for.
 Они создаются с использованием функций и инструкции yield.
def countdown():
  i=6
  while i > 0:
    yield i
    i -= 1
for i in countdown():
    print(i)
Инструкция yield определяет генератор, заменяет значение, возвращаемое функцией, и возвращает результат, не меняя первоначальные переменные
Так как генераторы возвращают по одному элементу за раз, они, в отличие от списков, не имеют ограничений по памяти.
 На самом деле, они могут выполняться бесконечно!
def infinite_sevens():  
  while True:  
    yield 7
for i in infinite_sevens():
    print(i)
Подсуммируем: генераторы позволяют объявить функцию, которая подобна итератору, т.е. может быть использована в цикле.
Конечные генераторы могут быть преобразованы в списки, для этого их нужно передать как аргументы функции list.
def numbers(x):
    for i in range(x): 
        if i % 2 == 0:
            yield i
print(list(numbers(111)))
Использование генераторов позволяет повысить производительность: «ленивая» генерация значений (генерация по требованию) означает сниженное потребление памяти. Кроме того, не нужно ждать, пока все элементы будут сгенерированы, мы можем начать их использовать гораздо раньше.