[Tutor] List Comprehension Syntax

Steven D'Aprano steve at pearwood.info
Sun Dec 23 14:27:33 CET 2012


On 23/12/12 18:48, Mario Cacciatore wrote:
> Hey everyone,
>
> I am having a very hard time understanding the list comprehension syntax.
>I've followed the docs and could use some guidance from the fine folks
>here to supplement my findings. If someone wouldn't mind replying back
>with an example or two, with some explanation of each part I'd appreciate
>it.


If you did mathematics in high school, you may remember set-builder notation:

http://en.wikipedia.org/wiki/Set-builder_notation

There are a number of variations of this notation, depending on how formal
you want to be. For example:

{3x+1 ∀ x ∈ {1, 2, 3}}

This says:

"build the set of values 3 times x plus 1, for all x values that are elements
of the set {1, 2, 3}"

and it would produce the values:

x=1 -> 3*1 + 1
x=2 -> 3*2 + 1
x=3 -> 3*3 + 1}

giving the final set {4, 7, 10}


Python uses similar notation, except based on English words instead of
mathematical symbols. In Python, we generally use lists or tuples, not sets,
so the list comprehension would be:

[3*x + 1 for x in (1, 2, 3)]


We can pull this apart to see what each part does.

[ ]

   The square brackets build a list.

3*x + 1

   This is the list comprehension expression. It is evaluated each time
   the list comp goes through the loop.

for x in (1, 2, 3)

   This sets up the list comprehension loop, and defines the loop
   variable, just like a for-loop. The tuple (1, 2, 3) is the loop
   sequence, x takes each value from this in turn.


So this list comprehension is equivalent to this for-loop:


tmp = []
for x in (1, 2, 3):
    tmp.append(3*x + 1)



except that you don't need to define a temporary list to accumulate the
results, the list comprehension does that for you.


List comprehensions can be more complicated. They can also take one or
more "if" clause:


[2*n for n in range(10) if n%2 == 1]


is equivalent to this for-loop:

tmp = []
for n in range(10):
     if n%2 == 1:
         tmp.append(2*n)



and so it will produce the list:

[2, 6, 10, 14, 18]


Naturally, you can use any sequence or iterable in the for-loop
part of list comps:

myname = "Quentin"
[c for c in myname if c.lower() != "q" if c.upper() != "T"]


will give

['u', 'e', 'i', 'n']


The sequence can even be another list comprehension:


[y+1 for y in [2*x for x in (1, 2, 3)] if y < 5]


gives [3, 5], and is equivalent to this pair of loops:


tmp1 = []
tmp2 = []
for x in (1, 2, 3):
     tmp1.append(2*x)
for y in tmp1:
     if y < 5:
         tmp2.append(y+1)



List comps can also take multiple loops:

[(a, b) for a in range(3) for b in range(3)]


gives this result:

[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]


and is equivalent to this nested loop:


tmp = []
for a in range(3):
     for b in range(3):
         tmp.append( (a, b) )



List comprehensions are powerful and compact, but because they are so compact,
they can also be hard to read. Resist the temptation to write every for-loop
as a list comprehension! Keep your list comps simple, and you will not regret
it. Nobody has ever said, "I wish my list comprehensions were more complicated
and hard to read!"



-- 
Steven


More information about the Tutor mailing list