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