range() in Python: start, stop, and step
range() is a lazy number generator. Its three arguments — start, stop, step — let you lay out anything on a grid, like a wave at perfectly even x-positions.
The big idea
range(start, stop, step) yields numbers from start, increasing by step, up to but not including stop.
See it in code
Start by seeing what range yields. Wrap it in list(...) to force the values out: one argument counts from 0, two arguments set a start and a stop:
print("range(4):", list(range(4)))
print("range(2, 6):", list(range(2, 6)))range(4): [0, 1, 2, 3] range(2, 6): [2, 3, 4, 5]
range(4) is 0…3; range(2, 6) is 2…5. In both, the stop value itself never appears — that exclusive stop is the rule that trips everyone up.
The third argument, step, sets the gap between values — which is exactly what controls even spacing. Same start, different step, different spread:
print("step 40:", list(range(0, 200, 40)))
print("step 88:", list(range(0, 400, 88)))step 40: [0, 40, 80, 120, 160] step 88: [0, 88, 176, 264, 352]
Bump the step from 40 to 88 and the values spread out. That's the knob we're about to use to space enemies evenly across the screen.
Now let range produce the positions directly. range(40, 480, 88) starts at 40, jumps by 88 each pass, and stops before 480 — and each value it yields is an x-position for an enemy:
from game import Stage, Enemy
screen = Stage.create()
Stage.clear(screen)
print("x positions:", list(range(40, 480, 88)))
for x in range(40, 480, 88):
Enemy(x, 90).draw(screen)x positions: [40, 128, 216, 304, 392]

Five positions, evenly spaced, and 480 itself never appears — stop is exclusive, just like the warm-ups. The next value would have been 480, off the right edge anyway. That exclusive-stop rule is exactly what makes range line up with pixel widths.
The three-arg form is a workhorse: range(0, 100, 10) for tick marks, range(len(prices)) to index a series, range(10, 0, -1) to count down. It never builds the full list in memory — it produces values on demand, so range(1_000_000) costs almost nothing until you loop it.
Try it yourself
Change the step to 74 and the spacing tightens. Then count backward with range(5, 0, -1) and print it — a negative step reverses direction. Wrap range in list(...) any time you want to see the values.
The common mistake
Off-by-one from the exclusive stop. range(1, 6) is 1, 2, 3, 4, 5 — five numbers, and 6 is not included. When you want positions 0 through n, you need range(n + 1).
What it unlocks
Precise counting drives for loops, grids via nested loops, and one-line builders with list comprehensions.