range()

A memory-efficient arithmetic progression — the standard tool for "iterate N times" or "count from a to b".

Built-in functionPython 1.0+Live demo
Common call
for i in range(n):
Returns
range object — iterable, sized, indexable, sliceable — but NOT a list
Replaces
the manual `while i < n: i += 1` pattern
Watch out
stop is EXCLUSIVE; step of 0 raises; negative step needs start &gt; stop or you get empty
range(stop) / range(start, stop[, step])
range

Demo

Live evaluation
Try:
Inputs
startintinclusive start (empty = 0)
stopintexclusive end
stepintstep (empty = 1)
Output
range(None, 5)
[0, 1, 2, 3, 4]

range produces the sequence start, start+step, start+2*step, ... stopping BEFORE it reaches stop. That half-open interval matches slicing conventions. Positive step counts up until stop is reached or exceeded; negative step counts down; a step in the wrong direction (say, negative when start &lt; stop) produces an empty range. The demo shows the values as a list for clarity — real code iterates a range object directly.

Parameters

NameTypeRequiredDescription
startintno (0)The first value in the sequence (inclusive). Omitted → 0.
stopintyesThe exclusive upper bound. The sequence stops BEFORE reaching this value.
stepintno (1)The increment between consecutive values. Must be non-zero — 0 raises ValueError. Negative steps count downward.

Return value

rangeA lazy sequence of integers from start (inclusive) to stop (EXCLUSIVE) stepping by step. Not a list — a `range` object that supports iteration, indexing, len(), and slicing. Memory-efficient: only start/stop/step are stored.

Common patterns

Fixed-count loop
The most common use — iterate exactly n times.
for i in range(n):
    do_step(i)
Countdown
Negative step counts backward.
for i in range(10, 0, -1):
    print(i)
Index and value with enumerate
For iterating a list with both index and value, prefer enumerate to `for i in range(len(x))`.
for i, item in enumerate(items):
    process(i, item)
Slicing a range
range objects support slicing — the result is another range.
r = range(100)
first_ten = r[:10]      # range(0, 10)
every_third = r[::3]    # range(0, 100, 3)

Examples

1. Basic
list(range(5))
Returns
[0, 1, 2, 3, 4]
2. From 2 to 10
list(range(2, 10))
Returns
[2, 3, 4, 5, 6, 7, 8, 9]
3. Even numbers
list(range(0, 20, 2))
Returns
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
4. Countdown
list(range(10, 0, -1))
Returns
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
5. Negatives
list(range(-3, 4))
Returns
[-3, -2, -1, 0, 1, 2, 3]
6. Empty (start=stop)
list(range(5, 5))
Returns
[]
7. Wrong direction
list(range(0, 5, -1))
Returns
[]
8. Step of zero raises
range(0, 5, 0)
Returns
ValueError: range() arg 3 must not be zero

Pitfalls

1. stop is EXCLUSIVE — the classic off-by-one
range(n) produces 0, 1, ..., n-1 — it does NOT reach n. Great for indexing, misleading when you counted up in your head.
Missing last value
list(range(1, 5))
[1, 2, 3, 4] # 5 is not included
Inclusive end
list(range(1, 6))
[1, 2, 3, 4, 5]
2. Wrong-direction step gives EMPTY, not an error
range(0, 5, -1) produces nothing — silent no-op. If you meant to count down, put the larger value first.
Empty silently
list(range(0, 5, -1))
[]
Reverse direction
list(range(5, 0, -1))
[5, 4, 3, 2, 1]
3. Step of zero raises ValueError
A zero step would loop forever — Python rejects it up front.
Zero step
range(0, 10, 0)
ValueError: range() arg 3 must not be zero
Non-zero
range(0, 10, 1)
range(0, 10)
4. range is NOT a list
Iterating works; indexing works; len works; slicing works. But `range(5) == [0, 1, 2, 3, 4]` is False — the objects have different types. Wrap in list() for equality tests against lists.
Wrong type
range(5) == [0, 1, 2, 3, 4]
False
Convert
list(range(5)) == [0, 1, 2, 3, 4]
True
5. range only works with integers
Float arguments raise TypeError. For a range of floats, use a comprehension or numpy.
Float rejected
range(0.0, 1.0, 0.1)
TypeError: 'float' object cannot be interpreted as an integer
Comprehension
[i * 0.1 for i in range(10)]
[0.0, 0.1, 0.2, ..., 0.9]

When to use

Use it
  • &quot;Do this N times&quot; — the fixed-count loop
  • Counting up or down with a fixed step
  • Slicing indices you will later apply to a sequence
  • Memory-efficient iteration over arithmetic progressions
Reach for something else
  • Iterating a list with index AND value → enumerate is idiomatic
  • Float progressions → comprehension or numpy
  • Non-uniform sequences → build a list explicitly
  • `range(len(x))` when you actually want the items → iterate x directly

Notes

Complexity
O(1) to construct; O(n) to iterate
Return
A range object — constant memory regardless of length
CPython impl
Objects/rangeobject.c :: range_new
Memory
O(1) — only start/stop/step are stored, values are computed on demand
Thread-safe
Yes — range objects are immutable

FAQ

A type. `range(5)` calls the constructor and returns a range OBJECT. This is why `range` is not deprecated even though `list` is a type — both are called like functions.

History

1.0
range() built the list eagerly — same as list(range(...)) in Python 3.
2.2
xrange() introduced as a lazy alternative.
3.0
range became lazy (the old xrange behavior); xrange removed.