Суть yield и return

Объясните, пожалуйста, различия между yield и return. Естественно, я уже понял, что return после выхода из функции возвращает все значения, в то время как yield работает как генератор и генерирует значения на ходу. Но вот чего я не понял. Есть код:

def enumerate(data, counter):
    n = counter
    for element in data:
        yield n, element
        n += 1
data1 = [6, 8, 3, 1, 0, 2, 3]
for num, val in enumerate(data1, 1):
    print(num, val)

Почему, если вместо yield написать return, выдаст ошибку: "TypeError: cannot unpack non-iterable int object". Ведь если различие только в том, что return выдает все сразу, а yield работает как генератор, то и ошибки не должно быть.


Ответы (2 шт):

Автор решения: Danis

после return функция сразу завершается

в вашем примере если место yield поставить return то функция вернёт (6, 1) и цикл for попытается сделать так:

num, val = 6

Что конечно же привидет к ошибке:

TypeError: cannot unpack non-iterable int object

Если хотите чтобы ваш код работал с return то он должен выглядеть так:

def enumerate(data, counter):
    n = counter
    list_ = []
    for element in data:
        list_.append((n, element))
        n += 1
    return list_
→ Ссылка
Автор решения: vp_arth

Как только в функции появляется ключевое слово yield, она становится функцией, возвращающей генератор.

def foo():
  yield 1
  yield 2

gen = foo() # generator
gen.next() # 1
gen.next() # 2

Генераторы являются итераторами, поэтому можно пройтись по ним циклом for in(ну и всё остальное, что можно сделать с итераторами).

for i in foo():
  print(i)

# 1
# 2

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

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

→ Ссылка