Используются для экономии занимаемой памяти, это по сути все те же самые итераторы, представим что у нас есть функция которая возвращает список из 100 элементов:
def get_number():
return list(range(100))
x = get_number()
print(x.__sizeof__())Эта функция занимает 984 байт при том что формирует список из 100 чисел.
При помощи спец оператора yield мы указываем какую переменную следует
сделать значением итератора, которую этот итератор будет перебирать
значения это переменной при каждой итерации методом next()
def get_yield_number():
for x in range(100):
yield x
print('Это никогда не будет выведено ')
s = get_yield_number()
print('Функция-генератор: ', s)
print('Память функции-генератора: ', s.__sizeof__())
print(next(s))
print(next(s))
print(next(s))В функции мы создаем цикл в котором генерируем последовательность, и при
помощи оператора yield указываем возвращаемое значение, именно это
значение и будет возвращаться каждый раз когда мы будем вызывать
следующую итерацию этой функции методом next()
В результате вывода видим, что функция использующая оператор yield
становится объектом генератором, и при помощи перебора методом next()
мы можем вызвать все элементы последовательности из функции, и при
всем этом благодаря тому что список не хранится в памяти, а генерирует
значение при обращении к нему, занимаемая память будет всего 64 байта.
Функция-генератор: <generator object func1.<locals>.get_yield_number at 0x7f0605c4fdb0>
Память функции-генератора: 64
0
1
2
3
Используя оператор yield мы создаем итерируемый объект, по которому
можно пройтись только один раз, и итератор будет сдвигаться каждый раз
при обращении к циклу, слово test будет выведено один раз, а далее
при обращении каждый раз будет выводиться новое число.
def a():
print('test')
for i in range(10):
yield i
for i in a():
print(i)
# Вывод
# test
# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9