will be helpful for those in need The object returned by range() (or xrange() in Python2.x) is known as a lazy iterable. Instead of storing the entire range, [0,1,2,..,9], in memory, the generator stores a definition for (i=0; i<10; i+=1) and computes the next value only when needed (AKA lazy-evaluation).
# this is a list, create all 5000000 x/2 values immediately, uses 
lis = [x/2 for x in range(5000000)]
# this is a generator, creates each x/2 value only when it is needed, uses ()
gen = (x/2 for x in range(5000000))
# this is also a generator, it will run until a yield occurs, and return that result.
# on the next call it picks up where it left off and continues until a yield occurs...
num = 0
while num < n:
num += 1
# same as (x/2 for x in range(5000000))