List comprehension with range() is one of Python’s most common and powerful patterns — it lets you generate new lists of numbers (or derived values) in a single, concise line by combining range() (for number sequences) with transformations and optional filtering. It’s faster, cleaner, and more readable than a for loop + append() for simple cases, and it’s used everywhere from quick math lists to data generation, indexing, and preprocessing.
In 2026, this pattern remains a Python staple — especially with type hints, large ranges in data science, and modern tools like Polars. Here’s a complete, practical guide to using list comprehensions with range(): basic generation, filtering, real-world patterns, performance tips, and best practices for clarity and safety.
The basic form creates a sequence of numbers (or computed values) directly from range() — no loop needed.
# Simple numbers 0 to 9
nums = [x for x in range(10)]
print(nums) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Squares of 1 to 10
squares = [x ** 2 for x in range(1, 11)]
print(squares) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Add a condition with if at the end — only include items that pass the test. This is equivalent to filtering inside a loop.
# Even numbers from 2 to 20
even_numbers = [num for num in range(2, 21) if num % 2 == 0]
print(even_numbers) # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# Multiples of 5 up to 100
multiples_of_5 = [x for x in range(100 + 1) if x % 5 == 0]
print(multiples_of_5) # [0, 5, 10, 15, ..., 100]
Real-world pattern: generating indices, coordinates, or test data — very common in data science, plotting, simulations, and preprocessing.
# Create x/y coordinates for a grid (0 to 4)
grid_points = [(x, y) for x in range(5) for y in range(5)]
print(grid_points[:5]) # [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4)]
# Generate timestamps or IDs
ids = [f"user_{i:04d}" for i in range(1, 101)]
print(ids[:3]) # ['user_0001', 'user_0002', 'user_0003']
Another everyday use: filtering and transforming numeric sequences — e.g., cleaning data, creating feature vectors, or preparing ranges for plotting.
# Positive even numbers up to 50, doubled
positive_evens_doubled = [num * 2 for num in range(1, 51) if num % 2 == 0]
print(positive_evens_doubled[:5]) # [4, 8, 12, 16, 20]
Best practices make list comprehensions with range() readable, efficient, and safe. Keep them short and simple — one expression, one if at most; if logic grows (>1–2 lines, needs statements, or multiple conditions), switch to a regular for loop with append(). Use meaningful variable names — [price * quantity for price, quantity in items] — never [x * y for x, y in z]. Add type hints for clarity — list[int] or list[float] — improves readability and IDE/mypy support. Prefer generator expressions (x for x in range(10)) when passing to sum(), max(), or list() — they’re memory-efficient and lazy. Modern tip: for very large ranges, avoid materializing huge lists — use generators or Polars lazy frames instead. In production, when generating indices for external data (files, APIs), wrap in try/except — handle overflow or invalid ranges gracefully. Combine with enumerate() for indexed ranges — [(i, x**2) for i, x in enumerate(range(10))].
List comprehensions with range() are Python’s concise, fast way to generate numeric sequences and derived lists — elegant for math, indexing, data prep, and testing. In 2026, use them with type hints, keep them simple, and switch to loops for complex logic. Master this pattern, and you’ll create clean, efficient lists from ranges in seconds.
Next time you need a list of numbers or computed values — reach for [... for x in range(...)]. It’s Python’s cleanest way to say: “Generate this sequence for me.”