Menu

Python range(): Start, Stop, Step, and Counting Down

How range() works in Python — start, stop, step, negative ranges, and why it's lazy rather than materializing a list.

A Tool for Producing Numbers

range() does exactly one thing: it produces a sequence of integers. It's the go-to partner for for loops when you need to iterate a specific number of times or walk a numeric interval.

The simplest form takes a single argument — the stop value:

main.py
Output
Click Run to see the output here.

Output:

0
1
2
3
4

Two details that catch newcomers:

  1. Counting starts at 0. range(5) gives you five numbers, starting from 0.
  2. The stop value is exclusive. range(5) stops before 5 — it doesn't include 5 itself.

These rules are consistent across Python's slicing, indexing, and range operations. Once you internalise "stop is exclusive," it stops tripping you up.

Three Forms

range() accepts one, two, or three arguments:

main.py
Output
Click Run to see the output here.

Step is the size of each jump. range(0, 20, 4) produces every fourth number. Keep that in mind the next time you need "every other item" or "every tenth sample."

Counting Down

The step can be negative, which lets you count backwards:

main.py
Output
Click Run to see the output here.

Again, the stop is exclusive — range(10, 0, -1) stops before 0, not at 0. To include 0, make the stop -1:

main.py
Output
Click Run to see the output here.

range Is Lazy

In Python 3, range() doesn't build a list of numbers in memory. It returns a lightweight range object that produces numbers one at a time, on demand. That's why you can write:

main.py
Output
Click Run to see the output here.

A billion-number "range" takes essentially no memory. The numbers are generated as the loop asks for them.

If you actually need a list of the numbers — because you want to modify it, sort it, or index into it beyond the basics — convert explicitly:

main.py
Output
Click Run to see the output here.

Most of the time, you don't need the list. for i in range(...) works directly.

Common Patterns

A handful of recipes you'll use constantly:

Do something n times.

main.py
Output
Click Run to see the output here.

The _ is a convention meaning "I don't care about this value" — Python doesn't enforce it, but any reader will recognize the intent.

Index into a sequence.

Prefer enumerate() over range(len(...)), but when you specifically need just the index:

main.py
Output
Click Run to see the output here.

Still, most of the time enumerate(items) is cleaner.

Iterate over every other element.

main.py
Output
Click Run to see the output here.

That prints a, c, e. For simple slicing, though, the slicing syntax is even more direct: items[::2].

Generate a quick numeric list.

main.py
Output
Click Run to see the output here.

That's a list comprehension — covered later — but range is what supplies the numbers.

What range() Is Not

Two sharp edges worth knowing:

  1. range only produces integers. If you need floating-point steps (like 0.0 to 1.0 in increments of 0.1), use numpy.arange or a loop with your own counter.
  2. range doesn't work with arbitrary iterables. It's specifically for integers. If you're trying to "range" over a list, you're probably looking for enumerate or just the list itself.

Putting It Together

A small example using several variations in one go:

main.py
Output
Click Run to see the output here.

Two nested range-driven loops, producing a grid. Notice that both loops start at 1 — range(1, 6) — because we want labels from 1 through 5.

Moving Into Collections

You've now seen conditions, both kinds of loops, and range. That's enough control flow to drive any collection. Next chapter: the collections themselves — lists, tuples, sets, and dictionaries.

Frequently Asked Questions

What does range() do in Python?

range() produces a sequence of integers. range(n) gives 0 through n-1. range(start, stop) gives integers from start up to but not including stop. range(start, stop, step) lets you choose the step size, including negative steps for counting down.

Does range() create a list?

No. In Python 3, range() returns a lightweight range object that generates numbers on demand. This is why range(10**9) is instant — it doesn't actually allocate a billion integers. Wrap it in list(...) if you really need a list.

How do I count down with range() in Python?

Use a negative step: range(10, 0, -1) counts 10, 9, 8, ..., 1. Remember that the stop value is always exclusive, so to include 0 you'd need range(10, -1, -1).

Learn to code with Coddy

GET STARTED