Double Iteration in List Comprehension

Here’s something I didn’t know possible in Python: iteration over more than one iterable in a list comprehension:

>>> seq_x = [1, 2, 3, 4]
>>> seq_y = 'abc'
>>> [(x,y) for x in seq_x for y in seq_y]
[(1, 'a'), 
(1, 'b'),
(1, 'c'),
(2, 'a'),
(2, 'b'),
(2, 'c'),
(3, 'a'),
(3, 'b'),
(3, 'c'),
(4, 'a'),
(4, 'b'),
(4, 'c')]

Cool, isn’t it? It’s equivalent to the following snippet:

>>> result = [] 
... for x in seq_x:
...     for y in seq_y:
...         result.append((x,y))
>>> result
[(1, 'a'),
(1, 'b'),
(1, 'c'),
(2, 'a'),
(2, 'b'),
(2, 'c'),
(3, 'a'),
(3, 'b'),
(3, 'c'),
(4, 'a'),
(4, 'b'),
(4, 'c')]

It also supports both “if” statements and referencing the outer iterator from the inner one, like so:

>>> seq = ['abc', 'def', 'g', 'hi'] 
... [y for x in seq if len(seq) > 1 for y in x if y != 'e']
['a', 'b', 'c', 'd', 'f', 'g', 'h', 'i']

This is equivalent to the snippet:

>>> result = [] 
... for x in seq:
...     if len(seq) > 1:
...         for y in x:
...             if y != 'e':
...                 result.append(y)
... result ['a', 'b', 'c', 'd', 'f', 'g', 'h', 'i']

The thing you should notice here, is that the outer loop is the first ‘for’ loop in the list comprehension. This was a little confusing for me at first because when I nest list comprehensions it’s the other way around.

To read more about this feature, check out this StackOverflow thread or the Python Manual.