Skip to content

Comprehensions

List comprehensions are one of Python's best features.

List and Dict Comprehension

A list comprehension is a compact way to build a new list from an existing iterable. Say I have a list of project names and I want a list of their slugs:

Python
project_names = ["Payments API", "Developer Portal", "Ops Console"]
slugs = [name.lower().replace(" ", "-") for name in project_names]
print(slugs)
# ['payments-api', 'developer-portal', 'ops-console']

The for loop equivalent does the same work in three lines:

Python
slugs = []
for name in project_names:
    slugs.append(name.lower().replace(" ", "-"))

The comprehension reads as "the slug for each name in project_names," which is closer to how I'd describe the result out loud.

You can also add an if filter to keep only the items you want:

Python
tasks = [
    {"title": "ship docs", "done": False},
    {"title": "cut release", "done": True},
    {"title": "announce launch", "done": False},
]

open_titles = [task["title"] for task in tasks if not task["done"]]
print(open_titles)
# ['ship docs', 'announce launch']

Dict comprehensions use a key: value expression:

Python
projects = ["Payments API", "Developer Portal", "Ops Console"]
slug_lookup = {name: name.lower().replace(" ", "-") for name in projects}
print(slug_lookup)
# {'Payments API': 'payments-api', 'Developer Portal': 'developer-portal', 'Ops Console': 'ops-console'}

Set comprehensions use curly braces with a single expression and give you back a set with no duplicates:

Python
raw_priorities = ["High", "high", "MEDIUM", "low", "Medium"]
unique_priorities = {p.lower() for p in raw_priorities}
print(unique_priorities)
# {'high', 'medium', 'low'}

A note on Generator comprehensions

Swap the square brackets for parentheses and you get a generator instead of a list:

Python
task_count = sum(1 for task in tasks if not task["done"])

A generator doesn't build the full list in memory. It produces one value at a time as the when the value is requested. It's done when the values run out.


Python
all_done = all(task["done"] for task in tasks)

If you need to iterate twice or index into the result, use a list comprehension. Generators give up random access in exchange for not allocating the whole sequence up front.

A more complex example

Python
normalized = [
    {
        "title": task["title"].strip().title(),
        "priority": task["priority"].strip().lower(),
        "done": bool(task["done"]),
    }
    for task in raw_tasks
]

Tip

Use a comprehension when:

  • you're looking to transform data
  • the logic is short
  • the result is easy to read

If the transformation starts getting hard to read, a normal for loop is often the better choice.

zip()

zip() is handy when you want to walk two collections together.

It produces an iterable of tuples, where each value from the two collections is paired up in order.

You can pass that into the dict constructor to. make a dictionary.

Python
field_names = ["name", "slug", "archived"]
field_values = ["Payments API", "payments-api", False]

zipped = zip(field_names, field_values)
project = dict(zipped)

That produces:

Python
{
    "name": "Payments API",
    "slug": "payments-api",
    "archived": False,
}