Comprehensions

INPUT · Slides

Keeping only the ones you want

01 / 06

You do not want all of them

"From a list of scores, collect only the ones that passed." This time it is not about changing every one but about keeping only some.

Written with for, you loop, check with if, and append only what gets through.

scores = [80, 45, 60]passes = []for s in scores:    if s >= 60:        passes.append(s)print(passes)

Result

[80, 60]

02 / 06

Add an if at the back

In a comprehension you only have to put if condition after the for.

[x for x in numbers if x > 0] is "for each x in numbers, a list of only the ones where x > 0".

Anything that fails the condition never goes into the new list, so what you get comes out shorter than what you started with.

numbers = [3, -1, 5, -2]print([x for x in numbers if x > 0])

Result

[3, 5]

03 / 06

Changing and filtering, in one line

The expression at the front and the if at the back work together.

"Only the ones above zero, doubled" fits on one line. The for version took five.

Read it right to left: the for tells you where they come from, the if tells you which are kept, and the expression at the front tells you what is made.

numbers = [3, -1, 5, -2]print([x * 2 for x in numbers if x > 0])

Result

[6, 10]

04 / 06

When you want the other case too

What about "positive if it is above zero and negative if it is not" — a value for either case?

That is not filtering, it is switching. Every item stays in the result, so the count comes out as it went in.

For that you use a if condition else b. a when the condition holds, b when it does not — one single expression.

number = 3print("positive" if number > 0 else "negative")

Result

positive

05 / 06

if alone goes behind, if with else goes in front

This is the part that muddles people. The if goes in a different place.

  • filtering (if alone) … after the for — [x for x in xs if x > 0]
  • switching (if with else) … before the for, where the expression is — [a if x > 0 else b for x in xs]

Remember it as "else means it goes in front". The version with else is itself the expression that decides what gets made, so it sits where what-gets-made goes: at the front.

numbers = [3, -1, 5, -2]print([x for x in numbers if x > 0])print(["positive" if x > 0 else "negative" for x in numbers])

Result

[3, 5]
['positive', 'negative', 'positive', 'negative']

06 / 06

You can have both at once

You can in fact write the if / else in front and the if at the back together.

But this is where it gets hard to read. Rather than cram it into one line, a plain for is sometimes the kinder thing. The test is "can somebody else take it in at a glance?"

Next lesson we put two fors side by side and deal with nesting.

scores = [80, 45, 60, 95]print([("excellent" if s >= 90 else "pass") for s in scores if s >= 60])

Result

['pass', 'pass', 'excellent']