[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