As you have discovered, the object created by the generator expression is an iterator (more precisely, an iterator-generator) intended to be used only once. If you need a resettable generator, just create a real generator and use it in loops:
def multiples_of_3(): # generator for i in range(100): yield i * 3 def multiples_of_7(): # generator for i in range(100): yield i * 7 list((i,j) for i in multiples_of_3() for j in multiples_of_7())
The second code works because the list of expressions of the inner loop ( (i*7 ...) ) is evaluated on each pass of the outer loop. This leads to the creation of a new iterator generator each time, which gives you the behavior you want, but at the cost of code clarity.
To understand what is happening, remember that there is no “reload” of the iterator when the for loop iterates over it. (This is a function, so reset aborts the iteration over the large iterator in parts, and this is not possible for generators.) For example:
multiples_of_2 = iter(xrange(0, 100, 2))
... by contrast:
multiples_of_2 = xrange(0, 100, 2)
The generation expression is equivalent to the called generator and therefore can only be repeated at a time.
source share