Skip to content

ይህ ትምህርት ገና ወደ አማርኛ አልተተረጎመም፤ ስለዚህ በእንግሊዝኛ ቀርቧል። የእንግሊዝኛውን ገጽ ክፈቱ

Comprehensions

3 min read

You've written the collect plan several times now: an empty list, a loop, an append. It's so common that Python has a one-line way to write it. By the end of this lesson you'll build lists, dicts, and sets in a single readable line, and know when a plain loop is still the better choice.

The collect loop, in one line

Here's the collect plan from lesson 4.2, adding a 5 birr delivery fee to every price:

prices = [250, 40, 1200]
with_fee = []
for price in prices:
    with_fee.append(price + 5)
print(with_fee)

In the editor, press Escape then Tab to move on.

And here's the same thing as a :

prices = [250, 40, 1200]
with_fee = [price + 5 for price in prices]
print(with_fee)

In the editor, press Escape then Tab to move on.

Read it aloud: "price + 5, for each price in prices". The parts are the same as the loop's, just rearranged: what goes into the new list comes first, then the for line. The square brackets say the result is a list. Change it so each price doubles.

After a for loop, its name still refers to the last item. A comprehension's name doesn't outlive it:

Keeping only some items

Add if at the end, and only the items that pass the test go in. This is the filter plan: collect only what passes. Predict this one.

ውጤቱን ገምቱ

Decide before you look. Guessing wrong is how this sticks.

scores = [45, 82, 67, 91, 38]
passed = [s for s in scores if s >= 50]
print(passed)
Pick the output

Python prints

[82, 67, 91]

The if decides which scores go in; each one that passes goes in as itself, because the expression before for is just s. You get a list of the passing scores, not True/False values, and not a count.

The same as a loop would be:

passed = []
for s in scores:
    if s >= 50:
        passed.append(s)

ጥያቄ

Which comprehension gives the even numbers from 1 to 10?

Dicts and sets too

With curly brackets and key: value before the for, you get a dict. With curly brackets and a single value, a set:

names = ["Hana", "Abel", "Selam"]
lengths = {name: len(name) for name in names}
print(lengths)
sizes = {len(name) for name in names}
print(sorted(sizes))

In the editor, press Escape then Tab to move on.

lengths pairs each name with its number of letters. sizes keeps each length once, because it's a set; that's why it's printed sorted (lesson 4.5).

When to use a loop instead

A comprehension is for one clear idea: make this from that, maybe with one test. When it stops fitting on one readable line, a loop is better. This works, but it takes a while to read:

report = [f"{name}: {score}" for name, score in zip(names, scores) if score >= 50 and name != "Abel"]

Written as a loop, each step gets its own line, and there's room for more later, like printing or counting along the way:

report = []
for name, score in zip(names, scores):
    if score >= 50 and name != "Abel":
        report.append(f"{name}: {score}")

Also use a loop when you want something to happen, like printing, rather than a new list. A comprehension's job is to build a collection.

መልመጃ

VAT on the big items

Add 15% VAT (multiply by 115, divide by 100) to each price, but only for items over 100 birr. Build the new list with one comprehension and print it.

Output
[287.5, 1380.0]

Your code

prices = [80, 250, 1200, 45]
# One comprehension: price with VAT, only for prices over 100

In the editor, press Escape then Tab to move on.

መፍትሄውን አሳይ

This is one way to solve it, not the only one. If yours prints the same thing, it works.

prices = [80, 250, 1200, 45]
with_vat = [price * 115 / 100 for price in prices if price > 100]
print(with_vat)

ዋና ዋና ነጥቦች

  • [expression for name in items] builds a list in one line: the collect plan.
  • Add if test at the end to keep only some items: the filter plan.
  • The comprehension's loop name doesn't exist after it.
  • {k: v for ...} builds a dict, and {v for ...} builds a set.
  • If it doesn't fit on one readable line, or you want to print rather than build, use a loop.