Коротко
Генератор — итератор, который лениво выдаёт значения через yield, не строя весь список в памяти.
def countdown(n):
while n > 0:
yield n
n -= 1
for x in countdown(3):
print(x)
Generator expression: (x * x for x in range(10**6)).
Зачем
Большие потоки данных, пайплайны, бесконечные последовательности.
Короткий ответ
«Функция с yield возвращает генератор: значения считаются по запросу, память не раздувается как у списка.»