The first example:
print([(letter,num) for letter in 'abc' for num in range(2)])
Prints a list (because of the outer []
brackets) which contains all the tuples (because of the parentheses around letter, num
) of letter
and num
for each value of letter
looping over 'abc'
and each value of num
looping over every value of the generator returned by range(2)
(which will be 0
and 1
).
Since Python takes the first for
as the outer loop, you see ('a', 0), ('a', 1),
etc. instead of ('a', 0), ('b', 0),
etc.
However, when you add parentheses around a for
expression like (letter,num) for letter in 'abc'
, you're no longer executing the loop in the comprehension, but you're capturing the generators (ready to start yielding their values, but not actually yielding the values into the comprehension).
So:
print([((letter,num) for letter in 'abc') for num in range(2)])
Here, ((letter,num) for letter in 'abc')
is just a generator that will yield values as soon as you start asking for them.
Note: because the value of num
is not enclosed in the generators separately, if you do something with them, you may see a surprising result:
x = [((letter,num) for letter in 'abc') for num in range(2)]
print(next(x[0]))
print(next(x[0]))
print(next(x[0]))
print(next(x[1]))
print(next(x[1]))
print(next(x[1]))
Result:
('a', 1)
('b', 1)
('c', 1)
('a', 1)
('b', 1)
('c', 1)