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

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

Функции-генераторы определяются так же, как и обычные функции, но они дополнительно содержат «генераторную» инструкцию. Она начинается с ключевого слова yield и определяет объект-генератор, который возвращается оператору, вызвавшему функцию. Когда генераторная инструкция исполняется, состояние объекта-генератора «замораживается» и сохраняется. Объект, возвращаемый генераторной инструкцией, может быть присвоен переменной. С помощью встроенной функции next() можно, передав ей имя этой переменной, продолжить выполнение функции с той самой точки заморозки.

Повторный вызов генератора с помощью функции next() продолжает исполнение функции до тех пор, пока не вызовется исключение. Его можно избежать, поместив генераторную инструкцию внутрь бесконечного цикла. Например, чтобы сгенерировать значения с приращением на каждом новом вызове, запишем:

def incrementer():
    i = 1
    while True:
        yield i
        i += 1
inc = incrementer()
print(next( inc ))
print(next( inc ))
print(next( inc ))

Эти последовательные вызовы функции выведут целые значения 1, 2 и 3.

Наиболее эффективным будет размещать объект-генератор в цикле, осуществляющем последовательные итерации по значениям.

import random
def lottery():
    # возвращает 6 случайных чисел от 1 до 40
    for i in range(6):
        yield random.randint(1, 40)
    # возвращает 7 число от 1 до 15
    yield random.randint(1,15)

for random_number in lottery():
    print("Следующий номер... %d!" %(random_number))