The range() Function#
Python’s range() produces a sequence of integers on demand. Paired with
for, it covers every counter-based loop pattern.
One-Argument Form: range(n)#
range(n) → 0, 1, 2, ..., n-1
Run it live and change n:
>>> for i in range(4):
... print(i)
...
0
1
2
3
To see the full sequence at once, convert it to a list:
>>> print(list(range(4)))
[0, 1, 2, 3]
Two-Argument Form: range(start, stop)#
range(start, stop) → start, start+1, ..., stop-1
Run it live:
>>> for i in range(1, 6):
... print(i)
...
1
2
3
4
5
Note that stop is exclusive — the loop runs while i < stop.
Three-Argument Form: range(start, stop, step)#
range(start, stop, step) → start, start+step, start+2*step, ...
Counting by fives from 0 to 20. Run it and change the step:
>>> print(list(range(0, 25, 5)))
[0, 5, 10, 15, 20]
The sequence stops before it would equal or exceed stop.
The boundaries of range() are the classic source of off-by-one bugs.
Change start, stop, and step and watch which integers appear:
>>> print(list(range(5))) # 0 .. 4
[0, 1, 2, 3, 4]
>>> print(list(range(1, 6))) # 1 .. 5 (stop is exclusive)
[1, 2, 3, 4, 5]
>>> print(list(range(0, 25, 5))) # count by fives
[0, 5, 10, 15, 20]
>>> print(list(range(5, 0, -1))) # count down
[5, 4, 3, 2, 1]
>>> for i in range(1, 6):
... print(i, end=" ")
...
1 2 3 4 5
Reverse Iteration#
A negative step counts downward. Run it live:
>>> for i in range(5, 0, -1):
... print(i)
...
5
4
3
2
1
range(n-1, -1, -1) visits indices n-1 down to 0.
An alternative that reads more naturally is reversed(range(n)):
>>> for i in reversed(range(5)):
... print(i)
...
4
3
2
1
0
Range Objects Are Lazy#
range() does not build a list in memory — it computes each integer on
demand. This makes range(1_000_000) just as cheap to create as
range(5). Only use list(range(...)) when you actually need a list.
Summary#
Pattern |
Python |
|---|---|
Count from 0 to n-1 |
|
Count from a to b-1 |
|
Count from a to b-1 by k |
|
Count down from n-1 to 0 |
|