Python range() creates an immutable sequence of integers. It is most commonly used with a for loop, but it is also useful for repeated actions, reverse counting, index generation, slicing-like patterns, and memory-efficient numeric sequences.
The function looks simple, yet many beginner errors come from misunderstanding its stopping value or step. This guide explains every form of range(), shows practical examples, and clarifies when another approach such as enumerate() is cleaner.
Basic syntax
The official Python range documentation defines three accepted forms:
range(stop)
range(start, stop)
range(start, stop, step)All arguments must be integers or integer-like objects. The sequence includes start but excludes stop. This half-open convention is central to Python and also appears in slicing, which is covered in our Python slicing guide.
Use range(stop)
With one argument, the sequence starts at zero:
for number in range(5):
print(number)The output is:
0
1
2
3
4The value 5 is not included. The sequence contains exactly five integers, which makes it convenient when an action must run five times:
for _ in range(5):
print("Processing...")The underscore indicates that the loop variable is intentionally unused.
Use range(start, stop)
Two arguments define a custom starting value:
for number in range(3, 8):
print(number)This produces 3, 4, 5, 6, 7. To include the number 8, set the stopping value to 9:
for number in range(3, 9):
print(number)A useful mental model is: begin at start, continue while the next value is still before stop.
Use range(start, stop, step)
The third argument controls the distance between values:
for number in range(0, 11, 2):
print(number)The result is the even numbers from 0 through 10:
0
2
4
6
8
10A step cannot be zero:
range(1, 10, 0) # ValueErrorA zero step would never advance the sequence, so Python rejects it immediately.
Count backward
Use a negative step when the sequence must decrease:
for number in range(10, 0, -1):
print(number)
print("Go!")The start must be greater than the stop when the step is negative. This range ends at 1 because the stop value 0 is excluded.
The following range is empty:
list(range(1, 10, -1)) # []The sequence starts at 1 but a negative step moves away from 10. Python does not automatically reverse an inconsistent range.
Convert a range to a list
A range object displays its definition rather than every value:
numbers = range(1, 6)
print(numbers) # range(1, 6)Convert it when an actual list is required:
numbers = list(range(1, 6))
print(numbers) # [1, 2, 3, 4, 5]Do not convert automatically. A range is compact and generates values as needed, while a list stores every integer in memory. The difference matters for large sequences.
Why range is memory-efficient
This statement does not allocate a billion Python integers:
huge = range(1_000_000_000)The object mainly stores the start, stop, and step. It calculates a value when that position is requested. This is why range() works well in loops and why converting an enormous range to a list can consume excessive memory.
The Python tutorial section on range demonstrates the same iteration model.
Check length and membership
values = range(10, 31, 5)
print(len(values)) # 5
print(20 in values) # True
print(21 in values) # FalseMembership checks do not need to iterate through every integer one by one. Range objects use their arithmetic structure efficiently.
Access range values by index
A range behaves like a sequence:
values = range(10, 31, 5)
print(values[0]) # 10
print(values[-1]) # 30
print(values[1:4]) # range(15, 30, 5)Indexing and slicing return predictable values without turning the complete sequence into a list.
Use range in common loops
Repeat a task a fixed number of times
for attempt in range(1, 4):
print(f"Attempt {attempt} of 3")Formatted output is explained further in the Academify guide to debugging with Python f-strings.
Generate a multiplication table
number = 7
for multiplier in range(1, 11):
result = number * multiplier
print(f"{number} x {multiplier} = {result}")Sum a numeric interval
total = sum(range(1, 101))
print(total) # 5050Here the stop is 101 because the intended interval includes 100.
Create coordinate pairs
for row in range(3):
for column in range(4):
print(row, column)Nested loops are useful for grids and matrices but can grow expensive quickly. The broader Python loops guide explains nesting, break, continue, and loop else.
Range with list indexes
You can iterate through indexes:
languages = ["Python", "Java", "JavaScript"]
for index in range(len(languages)):
print(index, languages[index])This works, but enumerate() is usually clearer:
for index, language in enumerate(languages):
print(index, language)Use range(len(...)) when you genuinely need index arithmetic, such as comparing an item with the next item or updating positions. Use enumerate() when you simply need each value and its index.
Compare adjacent items
temperatures = [18, 21, 20, 24, 27]
for index in range(1, len(temperatures)):
previous = temperatures[index - 1]
current = temperatures[index]
change = current - previous
print(f"Day {index}: {change:+d}")Starting at 1 prevents index - 1 from accidentally referring to the last item through Python’s negative indexing.
Create ranges from user input
try:
start = int(input("Start: "))
stop = int(input("Stop: "))
step = int(input("Step: "))
if step == 0:
raise ValueError("Step cannot be zero")
for number in range(start, stop, step):
print(number)
except ValueError as error:
print(f"Invalid value: {error}")The exception handling guide explains why input conversion should catch specific errors rather than hiding every exception.
Range and comprehensions
A list comprehension can transform range values:
squares = [number ** 2 for number in range(1, 11)]
print(squares)Add a condition to keep only selected values:
multiples_of_three = [
number
for number in range(1, 31)
if number % 3 == 0
]See the Python list comprehensions guide for readability rules and generator alternatives.
Common mistakes
Expecting the stop value to be included
list(range(1, 5)) # [1, 2, 3, 4]Use range(1, 6) when 5 must be included.
Using a float
range(0, 5, 0.5) # TypeErrorrange() is an integer sequence. For decimal steps, use a carefully designed loop, NumPy, or another suitable numeric tool while considering floating-point precision.
Forgetting direction
range(10, 0) # empty because the default step is +1Use range(10, 0, -1).
Creating a list unnecessarily
for number in list(range(1_000_000)):
passIterate over the range directly unless another API specifically requires a list.
Using range when values are enough
for index in range(len(items)):
print(items[index])Prefer for item in items when the index is not used.
Practical mini-project: countdown timer logic
import time
seconds = 5
for remaining in range(seconds, 0, -1):
print(remaining)
time.sleep(1)
print("Time is up!")This small example combines a descending range with a fixed delay. Real graphical or asynchronous applications should avoid blocking the main interface, but the pattern clearly demonstrates start, stop, and negative step.
Conclusion
Python range() represents an efficient integer sequence defined by start, stop, and step. Remember that the stop is excluded, the step determines direction, and zero is invalid. Iterate over a range directly for memory efficiency, choose enumerate() when you need values with indexes, and convert to a list only when stored values are truly required.






