Santosh
Santosh

Reputation: 1

outputs of different list comprehensions in python 3.x

I was studying about list comprehension in Python and I am confused why this two codes are producing different outputs. CODE:

print([(letter,num) for letter in 'abc' for num in range(2)])
print([((letter,num) for letter in 'abc') for num in range(2)])

OUTPUT:

[('a', 0), ('a', 1), ('a', 2), ('a', 3), ('b', 0), ('b', 1), ('b', 2), ('b', 3), ('c', 0), ('c', 1), ('c', 2), ('c', 3), ('d', 0), ('d', 1), ('d', 2), ('d', 3)]

[<generator object <listcomp>.<genexpr> at 0x000002919E020F20>, <generator object <listcomp>.<genexpr> at 0x000002919E148C10>, <generator object <listcomp>.<genexpr> at 0x000002919E1489E0>, <generator object <listcomp>.<genexpr> at 0x000002919E148C80>]

Upvotes: 0

Views: 50

Answers (2)

Barmar
Barmar

Reputation: 780724

The first list comprehension is equivalent to nested loops:

result = []
for num in range(2):
    for letter in 'abc':
        result.append((letter, num))
print(result)

Each iteration of the nested loop produces in an element of the resulting list.

The second is equivalent to a single loop:

result = []
for num in range(2):
    result.append((letter, num) for letter in 'abc')
print(result)

Each iteration of the loop appends a generator object to the resulting list.

You could use a nested list comprehension, but then the result will be nested lists, not a flat list as in the first version.

print([list((letter,num) for letter in 'abc') for num in range(2)])
# output: [[('a', 0), ('b', 0), ('c', 0)], [('a', 1), ('b', 1), ('c', 1)]]

Upvotes: 0

Grismar
Grismar

Reputation: 31319

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)

Upvotes: 1

Related Questions