In Python List, you can read item one by one means iterate items. So List is iterable. Python iterator object must implement two special methods, __iter__() and __next__(), collectively called the iterator protocol. Most of built-in containers in Python like: list, tuple, string etc. are iterables.
A Generator is a function that returns an object (iterator) which we can iterate over, but one value at a time.
>>> my_list = [x**2 for x in range(3)]
>>> my_list
[0, 1, 4]
>>> my_generator = (x**2 for x in range(3))
>>> my_generator
<generator object <genexpr> at 0x7f05636a0570>
>>> for i in my_generator:
... print(i)
0
1
4
To create a generator function in Python, yield keyword is used instead of return statement in normal function. Generator function contains one or more yield statement which returns an object (iterator) but does not start execution immediately.
>>> def square():
... for i in range(5):
... yield i ** 2
>>> square_gen = square()
it can be iterated using next() function or used with for in loop which internally calls next function.
>>> next(square_gen)
0
>>> next(square_gen)
1
>>> for i in square_gen: # to get rest of the elements
... print(i)
4
9
16
Python executes code in generator function until it comes to a yield statement, then pauses and delivers the object. When you extract another object, Python resumes just after the yield and continues until it reaches another yield. It continues till end. As it only produces one item at a time. So it is memory efficient and used to represent Infinite stream.
Enjoy Python!!