Для того, что бы разобраться как работают генераторы, приведу пример как работают итераторы. Допустим есть некоторый список: list = [1, 2, 4, ... n] - это контейнер из n элементов. Значения в таком списке уже определены и находятся в памяти. Для обхода по нему используется цикл for.
for item in list:
print(item)
Вот как раз итератор позволяет нам не только обходить списки в цикле, но и создавать списки по определенному алгоритму (формуле). Например так:
list = [x*2 for x in range(n)]
list - значения посчитаны
Такой код тоже создаст список из n элементов со значениями, которые уже определены и помещены в память. В данном случае, каждый элемент списка в диапазоне от 0 до n будет умножен на 2. Важно помнить, что тут для использования инициализации списка с помощью итератора используются "[ ]". Т.е итератор это механизм, который позволяет нам итерировать по какой-то последовательности или объекту. Теперь рассмотрим генераторы. Тут есть некоторые отличия, хотя идея у них с итераторами общая. Для примера возьмем ту же самую формулу, что использовалась в прошлом примере.
generator = (x*2 for x in range(n))
generator - значения не посчитаны
for item in generator:
print(item)
В результате мы получаем некоторый объект, а не список, по которому можем так же пробежаться в цикле for. Важный момент в том, что в данном случае, мы используем уже "( )" в отличии от итераторов. Разница заключается в том, что когда мы инициализируем список с помощью итераторов, мы получаем полностью сгенерированный список с посчитанными значениями. В случае с генератором, значение высчитывается во время обращения к генератору, т.е на каждом шаге в цикле for. Генератор выполнит заданный алгоритм, посчитает одно значение и положит значение в переменную item. И так каждый раз. Итераторы следует использовать, когда у нас ограниченное и небольшое количество аргументов и не занимаем много памяти. Если же работа ведется с большим объемом данных, и есть риск забить всю память, лучше использовать генераторы, что бы не запихивать все данные в оперативную память. Генераторы создают аргументы на лету, что удобно при работе с bigdata или с машинным обучением.