In [15]:
# generators are iterable objects that return successive values on demand
# instead of storing them all like a list.

# there are two ways to make generators. first, generator comprehensions

g = (x for x in range(10))
g


Out[15]:
<generator object <genexpr> at 0x7f90286c89b0>

In [18]:
g.next()


---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-18-d7e53364a9a7> in <module>()
----> 1 g.next()

StopIteration: 

In [19]:
# the second one is using "yield" instead of "return" in a function

def gen_range(n):
    for i in range(n):
        yield i
        
g = gen_range(10)
g


Out[19]:
<generator object gen_range at 0x7f90286c8a50>

In [30]:
g.next()


---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-30-d7e53364a9a7> in <module>()
----> 1 g.next()

StopIteration: 

In [27]:
# a generator is iterable, but only once after which it is used up

g = gen_range(2)

for i in g:
    print i


0
1

In [28]:
for i in g:
    print i

In [31]:
# "yield" can occur anywhere in a function

def gen_range(n, before=0, after=0):
    yield before
    for i in range(n):
        yield i
    yield after
    
for x in gen_range(4, -1, -2):
    print x


-1
0
1
2
3
-2

In [32]:
# if you want to store everything that a generator generates, use "list" or "tuple"

list(gen_range(5))


Out[32]:
[0, 0, 1, 2, 3, 4, 0]

In [33]:
tuple(gen_range(5))


Out[33]:
(0, 0, 1, 2, 3, 4, 0)

In [34]:
# indexing does not work on generators

gen_range(5)[0]


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-34-a051550d1656> in <module>()
      1 # indexing does not work on generators
      2 
----> 3 gen_range(5)[0]

TypeError: 'generator' object has no attribute '__getitem__'

In [42]:
# but "in" does
g = gen_range(5)
75 in g


Out[42]:
False

In [134]:
# generators can run forever, so be very careful about converting them to lists or tuples;
# that will cause an infinite loop and your program will freeze

def count_forever():
    n = 0
    while True:
        yield n
        n = n + 1
        if n == 8:
            return
        
g = count_forever()
g


Out[134]:
<generator object count_forever at 0x7f90286c8be0>

In [144]:
g.next()


---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-144-d7e53364a9a7> in <module>()
----> 1 g.next()

StopIteration: