I'm trying to make a list comprehension from two generators
g1 = (a for a in range(3))
g2 = (b for b in range(5))
l = [(i, j) for i in g1 for j in g2]
print(l)
but instead of a list of 15 tuples it only returns results of the first inner loop.
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4)]
However, if to put the generators into the comprehension itself, the result is as expected.
l = [(i, j)
for i in (a for a in range(3))
for j in (b for b in range(5))]
print(l)
Do I miss something, or is it just a kind of a "feature"?
Here are cProfile outputs for both versions.
ncalls tottime percall cumtime percall filename:lineno(function)
4 0.000 0.000 0.000 0.000 t.py:1(<genexpr>)
1 0.000 0.000 0.000 0.000 t.py:1(<module>)
6 0.000 0.000 0.000 0.000 t.py:2(<genexpr>)
1 0.000 0.000 0.000 0.000 t.py:3(<listcomp>)
1 0.000 0.000 0.000 0.000 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {built-in method builtins.print}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 t.py:1(<listcomp>)
1 0.000 0.000 0.000 0.000 t.py:1(<module>)
4 0.000 0.000 0.000 0.000 t.py:2(<genexpr>)
18 0.000 0.000 0.000 0.000 t.py:3(<genexpr>)
1 0.000 0.000 0.000 0.000 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {built-in method builtins.print}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
CodePudding user response:
The generator can only be consumed ones. After that it is empty.
In your first example g1 is used for the first item of g2. For each further item of g2 it is already "used up" and returns nothing.
In your second example for each iteration of the outer loop a new fresh generator is created.
Further reading: Resetting generator object in Python
