range() in Python 2026: Efficient Sequence Generation + Modern Patterns & Best Practices
The built-in range() function generates an immutable sequence of integers — perfect for loops, indexing, slicing, and creating arithmetic progressions without materializing large lists in memory. In 2026 it remains one of the most memory-efficient and frequently used built-ins for controlled iteration, batch processing, array indexing, ML epoch/step counting, and algorithm implementation.
With Python 3.12–3.14+ delivering faster range iteration, better type hinting (improved generics for range), and free-threading compatibility for concurrent loops, range() is more performant and type-safe than ever. This March 24, 2026 update covers how range() works today, real-world patterns, performance advantages over list(range()), and best practices for clean, efficient, and lazy sequence generation in modern Python.
TL;DR — Key Takeaways 2026
range(start=0, stop, step=1)→ immutable sequence [start, start+step, ...] < stop- Lazy & memory-efficient — O(1) space, O(n) time only when consumed
- 2026 best practice: Prefer range() directly in for-loops; use list(range()) only when materialization is needed
- Main use cases: controlled loops, indexing, slicing, ML epoch/step counters, pagination
- Type-safe pattern:
range[int]from typing - Performance: Extremely fast creation & iteration — far better than list(range()) for large ranges
1. Basic Usage — Generating Sequences
# Simple range
for i in range(5):
print(i) # 0 1 2 3 4
# With start & step
print(list(range(10, 20, 2))) # [10, 12, 14, 16, 18]
# Reverse (negative step)
print(list(range(10, 0, -2))) # [10, 8, 6, 4, 2]
# Empty range
print(list(range(5, 5))) # []
2. Real-World Patterns in 2026
ML Epoch / Batch Indexing
def train_loop(epochs: int, batch_size: int):
for epoch in range(1, epochs + 1):
print(f"Epoch {epoch}/{epochs}")
for batch_idx in range(0, 1000, batch_size):
# process batch
pass
Pagination & Slicing Large Data
def paginate(items: list, page: int, size: int = 20):
start = (page - 1) * size
return items[start : start + size]
# Or generate page numbers lazily
for page_num in range(1, len(items) // size + 2):
print(f"Page {page_num}")
Indexed Parallel Processing (with zip & enumerate)
names = ["Alice", "Bob", "Charlie"]
scores = [95, 87, 92]
for idx, (name, score) in enumerate(zip(names, scores), start=1):
print(f"Rank {idx}: {name} ({score})")
3. range() vs Alternatives – Comparison 2026
| Approach | Memory | Laziness | Best For |
|---|---|---|---|
| range(start, stop, step) | O(1) | Lazy | Loops, indexing, large ranges |
| list(range(n)) | O(n) | Eager | When you need full list |
| numpy.arange() | O(n) | Eager array | Numeric arrays, ML |
| range in for-loop | O(1) | Lazy | Standard iteration |
4. Best Practices & Performance in 2026
- Use range() directly in for-loops — no need for list(range())
- Type hints 2026:
from typing import Iterator def count_up_to(n: int) -> Iterator[int]: return iter(range(n)) - Performance: range() is O(1) space — ideal for very large ranges
- Free-threading (3.14+): Safe for read-only iteration
- Avoid: list(range(large_n)) — wastes memory; use range() lazily
Conclusion — range() in 2026: Efficient Sequence Generator
range() is Python’s go-to for creating arithmetic sequences without wasting memory — the foundation of controlled loops, indexing, and batch processing. In 2026, use it directly in for-loops, combine it with enumerate() and zip() for powerful iteration, and rely on it in ML epoch counters, pagination, and data pipelines. It’s fast, memory-efficient, and one of Python’s most essential built-ins for performant, readable code.
Next steps:
- Replace any list(range()) in loops with plain range()
- Related articles: Efficient Python Code 2026 • Python Built-ins Overview 2026