Суть 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 шт):
после 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_
Как только в функции появляется ключевое слово 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.
Таким образом, мы можем, например, создавать бесконечные генераторы, выбирая из них нужно количество элементов, не опасаясь зацикливания.