Home > Software engineering >  Python3 list comprehension from two generators processes only the 1st inner loop
Python3 list comprehension from two generators processes only the 1st inner loop

Time:10-28

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

  • Related