List comprehensions are one of Python's most elegant features. They let you create new lists in a single, readable line. Generator expressions are their memory-efficient cousins.
Old way (verbose):
squares = []
for x in range(10):
squares.append(x**2)New way (Pythonic):
squares = [x**2 for x in range(10)]Both create [0, 1, 4, 9, 16, 25, 36, 49, 64, 81], but the comprehension is cleaner and faster.
[expression for item in iterable]Examples:
# Double each number
numbers = [1, 2, 3, 4, 5]
doubled = [n * 2 for n in numbers]
# [2, 4, 6, 8, 10]
# convert to uppercase
words = ["hello", "world"]
upper = [w.upper() for w in words]
# ['HELLO', 'WORLD']
# get lengths
words = ["cat", "dog", "elephant"]
lengths = [len(w) for w in words]
# [3, 3, 8]Add an if clause to filter items:
[expression for item in iterable if condition]Examples:
# Only even numbers
numbers = range(20)
evens = [n for n in numbers if n % 2 == 0]
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# only long words
words = ["cat", "elephant", "dog", "rhinoceros"]
long_words = [w for w in words if len(w) > 5]
# ['elephant', 'rhinoceros']
# positive numbers only
values = [-5, 3, -2, 8, -1, 10]
positives = [v for v in values if v > 0]
# [3, 8, 10]You can combine transformation and filtering:
# square only even numbers
numbers = range(10)
even_squares = [n**2 for n in numbers if n % 2 == 0]
# [0, 4, 16, 36, 64]
# uppercase only long words
words = ["cat", "python", "go", "javascript"]
upper_long = [w.upper() for w in words if len(w) > 3]
# ['PYTHON', 'JAVASCRIPT']Use a ternary expression for conditional values:
[true_value if condition else false_value for item in iterable]Examples:
# Label numbers as even/odd
numbers = range(5)
labels = ["even" if n % 2 == 0 else "odd" for n in numbers]
# ['even', 'odd', 'even', 'odd', 'even']
# cap values at maximum
values = [10, 50, 30, 80, 20]
capped = [v if v <= 50 else 50 for v in values]
# [10, 50, 30, 50, 20]
# replace negative with zero
numbers = [5, -3, 8, -1, 10]
positives = [n if n > 0 else 0 for n in numbers]
# [5, 0, 8, 0, 10]Create multi-dimensional structures:
# multiplication table
matrix = [[i*j for j in range(1, 6)] for i in range(1, 6)]
for row in matrix:
print(row)
# [1, 2, 3, 4, 5]
# [2, 4, 6, 8, 10]
# [3, 6, 9, 12, 15]
# [4, 8, 12, 16, 20]
# [5, 10, 15, 20, 25]
# flatten a nested list
nested = [[1, 2], [3, 4], [5, 6]]
flat = [num for sublist in nested for num in sublist]
# [1, 2, 3, 4, 5, 6]
# create coordinate pairs
coords = [(x, y) for x in range(3) for y in range(3)]
# [(0,0), (0,1), (0,2), (1,0), (1,1), (1,2), (2,0), (2,1), (2,2)]Same syntax works for sets and dicts:
# set comprehension (unique values)
numbers = [1, 2, 2, 3, 3, 3, 4]
unique_squares = {n**2 for n in numbers}
# {1, 4, 9, 16}
# dictionary comprehension
words = ["cat", "dog", "elephant"]
word_lengths = {w: len(w) for w in words}
# {'cat': 3, 'dog': 3, 'elephant': 8}
# invert a dictionary
original = {"a": 1, "b": 2, "c": 3}
inverted = {v: k for k, v in original.items()}
# {1: 'a', 2: 'b', 3: 'c'}Use () instead of [] to create a generator:
# list comprehension (creates entire list in memory)
squares_list = [x**2 for x in range(1000000)] # Uses lots of memory!
# generator expression (computes on demand)
squares_gen = (x**2 for x in range(1000000)) # Minimal memory!Why generators?
# create generator
gen = (x**2 for x in range(10))
# get values one at a time
print(next(gen)) # 0
print(next(gen)) # 1
print(next(gen)) # 4
# or use in a loop
gen = (x**2 for x in range(10))
for square in gen:
print(square)
# or convert to list when needed
gen = (x**2 for x in range(10))
all_squares = list(gen)Good uses:
# sum large sequence (doesn't need to store all values)
total = sum(x**2 for x in range(1000000))
# check if any value matches (stops at first match)
has_big = any(x > 100 for x in range(1000))
# chain operations without intermediate lists
processed = (
x * 2
for x in range(1000)
if x % 2 == 0
)When to use lists instead:
items[5]# extract valid emails
lines = ["user@example.com", "invalid", "admin@site.org", "bad@"]
emails = [line for line in lines if "@" in line and "." in line]# clean and format user input
inputs = [" Alice ", "BOB", "charlie "]
cleaned = [name.strip().title() for name in inputs]
# ['Alice', 'Bob', 'Charlie']# transpose a matrix
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
transposed = [[row[i] for row in matrix] for i in range(3)]
# [[1, 4, 7], [2, 5, 8], [3, 6, 9]]# process log file (generator for memory efficiency)
with open("huge_log.txt") as f:
errors = (line for line in f if "ERROR" in line)
for error in errors:
print(error.strip())import time
# list comprehension (stores all)
start = time.time()
squares_list = [x**2 for x in range(1000000)]
total = sum(squares_list)
print(f"List: {time.time() - start:.4f}s")
# generator (computes on demand)
start = time.time()
total = sum(x**2 for x in range(1000000))
print(f"Generator: {time.time() - start:.4f}s")Generators are often faster and always use less memory!
Extract specific fields:
users = [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25}
]
names = [u["name"] for u in users]
# ['Alice', 'Bob']Filter and transform:
prices = [10.5, 20.0, 5.5, 30.0]
discounted = [p * 0.9 for p in prices if p > 10]
# [18.9, 27.0]Combine multiple lists:
names = ["Alice", "Bob", "Charlie"]
scores = [95, 87, 92]
combined = [(n, s) for n, s in zip(names, scores)]
# [('Alice', 95), ('Bob', 87), ('Charlie', 92)]Too complex:
# bad - hard to read
result = [x*y for x in range(10) if x % 2 == 0
for y in range(10) if y % 3 == 0
if x + y < 15]
# better - use regular loop with comments
result = []
for x in range(10):
if x % 2 != 0:
continue
for y in range(10):
if y % 3 != 0:
continue
if x + y >= 15:
continue
result.append(x * y)Need to handle errors:
# bad - can't easily catch exceptions
values = [int(x) for x in inputs] # Crashes on non-numbers
# better
values = []
for x in inputs:
try:
values.append(int(x))
except ValueError:
print(f"Skipping invalid: {x}")[expr for item in iter]if: [expr for item in iter if condition]() for generators to save memory