List comprehensions are one of Python's most distinctive and powerful features. They allow you to create new lists from existing iterables in a single, readable expression, combining loop logic, filtering, and transformation into a compact syntax.
This guide covers everything you need to use list comprehensions effectively, from basic syntax and conditional filtering to nested loops, practical real-world examples, performance considerations, and knowing when a traditional for loop is the better choice.
Understanding the Basic Syntax
A list comprehension follows this general pattern:
new_list = [expression for item in iterable]It reads almost like English: "give me expression for each item in iterable."
Here is a simple example that squares each number in a range:
squares = [x ** 2 for x in range(10)]
print(squares)Output:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]The equivalent traditional loop requires more lines and an explicit .append() call:
squares = []
for x in range(10):
squares.append(x ** 2)
print(squares)Output:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]Both produce the same result, but the comprehension is more concise and, as you will see later, also faster.
Adding Conditional Filtering
You can filter which elements make it into the final list by adding an if clause after the iterable:
even_squares = [x ** 2 for x in range(10) if x % 2 == 0]
print(even_squares)Output:
[0, 4, 16, 36, 64]Only values of x that pass the condition (x % 2 == 0) are squared and included. This is equivalent to:
even_squares = []
for x in range(10):
if x % 2 == 0:
even_squares.append(x ** 2)You can also chain multiple if conditions. They act as logical AND:
results = [x for x in range(30) if x % 2 == 0 if x % 3 == 0]
print(results)Output:
[0, 6, 12, 18, 24]Using Conditional Expressions (if/else)
To apply different transformations based on a condition rather than filtering items out, use a ternary expression before the for keyword:
labels = ["even" if x % 2 == 0 else "odd" for x in range(5)]
print(labels)Output:
['even', 'odd', 'even', 'odd', 'even']Working with Nested Loops
List comprehensions support multiple for clauses. This is most commonly used to flatten nested structures. The loop order reads left to right, matching the order of equivalent nested for loops:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened)Output:
[1, 2, 3, 4, 5, 6, 7, 8, 9]The equivalent nested loop makes the ordering clearer:
flattened = []
for row in matrix: # outer loop comes first
for num in row: # inner loop comes second
flattened.append(num)Creating nested structures
You can also produce nested lists by placing a comprehension inside another comprehension:
multiplication_table = [[i * j for j in range(1, 4)] for i in range(1, 4)]
print(multiplication_table)Output:
[[1, 2, 3], [2, 4, 6], [3, 6, 9]]Here, the outer comprehension iterates over i, and for each i the inner comprehension builds a row by iterating over j.
Practical Examples
Filtering and transforming strings
words = ["Hello", "WORLD", "Python", "CODE"]
lowercase_long = [word.lower() for word in words if len(word) > 4]
print(lowercase_long)Output:
['hello', 'world', 'python']Extracting data from a list of dictionaries
users = [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25},
{"name": "Charlie", "age": 35},
]
senior_names = [user["name"] for user in users if user["age"] >= 30]
print(senior_names)Output:
['Alice', 'Charlie']Filtering file names by extension
files = ["report.pdf", "data.csv", "image.png", "notes.txt"]
text_files = [f for f in files if f.endswith((".txt", ".csv"))]
print(text_files)Output:
['data.csv', 'notes.txt']Cleaning and normalizing user input
raw_tags = [" Python ", "JAVA", " javascript ", "", " ", "Ruby"]
clean_tags = [tag.strip().lower() for tag in raw_tags if tag.strip()]
print(clean_tags)Output:
['python', 'java', 'javascript', 'ruby']The if tag.strip() filter removes empty strings and whitespace-only entries before the transformation runs.
Building a dictionary from two lists
Although this guide focuses on list comprehensions, it is worth noting that the same syntax works for dictionaries and sets:
keys = ["name", "age", "city"]
values = ["Alice", 30, "NYC"]
user_dict = {k: v for k, v in zip(keys, values)}
print(user_dict)Output:
{'name': 'Alice', 'age': 30, 'city': 'NYC'}Performance Considerations
List comprehensions are generally faster than equivalent for loops with .append(). This is because they are optimized at the bytecode level: the interpreter avoids repeated method lookups for .append() and uses an internal mechanism to build the list.
import timeit
time_comp = timeit.timeit("[x ** 2 for x in range(1000)]", number=10000)
time_loop = timeit.timeit(
"""
result = []
for x in range(1000):
result.append(x ** 2)
""",
number=10000,
)
print(f"Comprehension: {time_comp:.4f}s")
print(f"Loop: {time_loop:.4f}s")Output:
Comprehension: 2.1657s
Loop: 3.0289sCommon Mistakes to Avoid
Using a comprehension for side effects
List comprehensions are designed to build a new list. Using them solely to call a function for its side effect creates a throwaway list in memory and makes the intent unclear:
[print(x) for x in range(5)]
for x in range(5):
print(x)Overcomplicating the expression
If your comprehension becomes hard to read at a glance, break it out into a regular loop or a helper function:
result = [x.strip().lower().replace(" ", "_") for x in data if x.strip() and not x.startswith("#") and len(x) < 100]
def clean_entry(entry):
cleaned = entry.strip().lower().replace(" ", "_")
return cleaned
result = [clean_entry(x) for x in data if x.strip() and not x.startswith("#") and len(x) < 100]
result = []
for x in data:
stripped = x.strip()
if stripped and not stripped.startswith("#") and len(stripped) < 100:
result.append(stripped.lower().replace(" ", "_"))When to Use List Comprehensions vs. Regular Loops
| Scenario | Recommended Approach |
|---|---|
| Simple transformation or filter | List comprehension |
| Building a new list from an iterable | List comprehension |
| Complex logic with multiple branches | Regular for loop |
| Side effects (printing, writing to file) | Regular for loop |
| Very large datasets where you only iterate once | Generator expression |
| Nested logic deeper than two levels | Regular for loop or helper function |
Summary
List comprehensions provide a concise, readable, and performant way to create lists in Python. To use them effectively:
- Use the basic pattern
[expression for item in iterable]for straightforward transformations. - Add an
ifclause after the iterable to filter which items are included. - Place an
if/elseexpression before theforkeyword when you need to transform every item conditionally. - Use multiple
forclauses to flatten nested structures, reading the loops left to right. - Prefer generator expressions
(...)over list comprehensions[...]when you do not need to store the entire result in memory. - Avoid using comprehensions for side effects or when the logic becomes too complex to read in a single expression.
With practice, list comprehensions become a natural and powerful part of writing clean, idiomatic Python code.