Premature ending of generator in list comprehension

To get the desired result, the "inner" generator would have to be run as many times as the "outer" generator yields a value.

But, after the first run, the "inner" generator is exhausted and cannot be run again.

Adding a print illustrates this (simplifying the example):

>>> def inc(a, b):
...    for i in range(a, b):
...        print(i)
...        yield i
...
>>> a = inc(1, 4)
>>> b = inc(4, 7)
>>> [(i, j) for i in a for j in b]
1  # <-- a begins to run
4  # <-- b begins to run
5
6  # <-- b exhausted here
2  # <-- a continued, but not resulting in list item, because lacking value from b
3
[(1, 4), (1, 5), (1, 6)]

The reason why not storing the generators in variables works as expected is because a new "inner" generator is created for each iteration of the "outer" generator. Again, illustrated by some prints:

>>> def inc(a, b):
...    print('started', a, b)
...    for i in range(a, b):
...        yield i
... 
>>> [(i, j) for i in inc(1, 4) for j in inc(4, 7)]
started 1 4
started 4 7
started 4 7
started 4 7
[(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)]

The reason why using range objects or lists works as expected is because they can be iterated over arbitrarily many times without being exhausted.