Free Online Code Editor
Learn how Python list comprehensions work, with filtering, nested loops, dict and set versions, and clear rules for when a plain loop is the better choice.
A list comprehension is a short way to build a new list from an existing one. Once it clicks, you'll use it every day. Before it clicks, it looks like a puzzle.
Here's the plan: start from the loop you already know, turn it into a comprehension step by step, and then look at when you should not use one.
Say you want the squares of the numbers 1 through 5. With a regular loop:
squares = []
for n in range(1, 6):
squares.append(n * n)
print(squares)[1, 4, 9, 16, 25]The comprehension version does the same job in one line:
squares = [n * n for n in range(1, 6)]
print(squares)[1, 4, 9, 16, 25]Read it from left to right: "give me n * n for each n in the range." The pattern is always:
[expression for item in iterable]The expression is what goes into the new list. The for part says where the items come from.
Put an if at the end to keep only some items.
numbers = [3, 8, 11, 14, 21, 26]
evens = [n for n in numbers if n % 2 == 0]
print(evens)[8, 14, 26]The condition decides which items get in. Items that fail it are skipped, not replaced.
This trips people up. When you want to transform every item differently depending on a condition, the if/else goes at the front, because it's part of the expression:
scores = [92, 48, 75, 61, 30]
results = ["pass" if s >= 60 else "fail" for s in scores]
print(results)['pass', 'fail', 'pass', 'pass', 'fail']A quick memory aid: a lone if goes at the end and filters. An if/else goes at the front and transforms.
Comprehensions are great for cleaning up messy input.
raw = [" Alice ", "BOB", " carol", ""]
names = [name.strip().title() for name in raw if name.strip()]
print(names)['Alice', 'Bob', 'Carol']You can also pull one field out of a list of dictionaries:
users = [
{"name": "Ana", "age": 31},
{"name": "Ben", "age": 17},
{"name": "Cy", "age": 45},
]
adult_names = [u["name"] for u in users if u["age"] >= 18]
print(adult_names)['Ana', 'Cy']You can use more than one for. They read in the same order as nested loops would.
pairs = [(color, size) for color in ["red", "blue"] for size in ["S", "M"]]
print(pairs)[('red', 'S'), ('red', 'M'), ('blue', 'S'), ('blue', 'M')]To flatten a list of lists, it looks like this:
grid = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [value for row in grid for value in row]
print(flat)[1, 2, 3, 4, 5, 6, 7, 8, 9]The outer loop comes first (for row in grid) and the inner loop second. If you ever find that confusing, that's a hint to use a regular loop instead.
The same idea works with curly braces.
words = ["apple", "kiwi", "banana"]
lengths = {w: len(w) for w in words}
print(lengths)
first_letters = {w[0] for w in words}
print(sorted(first_letters)){'apple': 5, 'kiwi': 4, 'banana': 6}
['a', 'b', 'k']A dictionary comprehension uses key: value. A set comprehension has a single value and removes duplicates automatically.
Short and readable is the whole point. Skip the comprehension when:
for loop when you want to print or save things. A comprehension that builds a throwaway list is wasteful and confusing.sum() or any(), use a generator expression with round brackets. It doesn't build the list in memory.big_total = sum(n * n for n in range(1_000_000))
print(big_total)333332833333500000Compare these two. Which would you rather read six months from now?
# Hard to read
result = [y for x in data if x.active for y in x.items if y.price > 10 and y.stock]
# Easier
result = []
for x in data:
if not x.active:
continue
for y in x.items:
if y.price > 10 and y.stock:
result.append(y)The loop is longer, but anyone can follow it. Code gets read far more often than it gets written.
None results. [print(n) for n in range(3)] prints the numbers, but it also builds a list of None values you didn't ask for.[expression for item in iterable if condition].if filters. A leading if/else transforms.{}.Reading helps, but typing the code is what makes it stick. Open the editor, paste any example from this article, and change it until it breaks.
Open the Python editorA clear order for learning Python from zero, the topics you can safely ignore for now, and the mistakes that trip up almost every beginner.
Understand Python decorators by building a timer, a logger, a retry wrapper, and a cache, with the functools.wraps detail most tutorials skip.
See how Python generators and the yield keyword let you handle huge files and endless streams one item at a time, with clear examples and common gotchas.