Марк Лутц неоднократно писал о важности понимания генераторов и итераторов. Здесь я коротко изложу основные положения из важной главы № 20 книги "Изучаем python".
Отображение операций на последовательности и сбор результатов - очень частая задача. Можно это делать через:
- цикл for;
- функциональное программирование (например функция map);
- разовую функцию lambda.
- Но лучше всего через генератор списка. Пример:
res
[115,112,97,109]
В отличие от функции map генератор отображает выражение на последовательность и сразу выдаёт весь результат. Он гибкий (можно сделать вложенные циклы, можно обрабатывать вложенные списки т.е. матрицы) и быстрее всех аналогов.
Но может понадобится получать не все результаты сразу, а по требованию. Это возможно реализовать двумя способами.
Функция генератор и инструкция yield (глагол переводится как 'уступать').
Обычная функция возвращает всю последовательность сразу, после чего завершает работу.
Функция-генератор приостанавливает и возобновляет выполнение работы, воспроизводя последовательность значений. При вызове возвращается объект генератора.
def createGenerator():
mylist = range(3)
for i in mylist:
yield i*i # yield вместо return, т.е. замораживание состояния
mygenerator = createGenerator() # создать генератор
print(mygenerator)
<generator object createGenerator at 0xb7555c34> # выдаёт объект
for i in mygenerator: # итерируем объект но только 1 раз!
print(i)
0
1
4
g = (x ** 2 for i in range(4))
next(g)
0
next(g)
1
next(g)
2
next(g)
3
next(g)
StopIteration
Также в 3й версии языка добавились генераторы множеств и словарей. Они как генераторы списков - возвращают всю последовательность сразу.
Генератор множеств:
{x*x for x in range(5)}
{0,1,4,9,16}
Генератор словаря:
{x:x*x for x in range(5)}
{0:0, 1:1, 2:4, 3:9, 4:16}