🚀 Supercharge your YouTube channel's growth with AI.
Try YTGrowAI FreePython xrange: Meaning and Migration

Updating Python code that uses xrange() starts with knowing which Python version the code targets. In Python 2, xrange() provides an immutable integer sequence for loops, while Python 3 uses range() for that job.
This article explains what xrange() did and shows how to replace its calls with range() while keeping the same bounds.
TL;DR: Use range() in Python 3
Python 2 provided xrange() for a lazy integer sequence, while Python 3 uses range() for that job.
- Replace xrange(start, stop, step) with range(start, stop, step) in Python 3.
- Python 3 range is an immutable sequence, not a list or an iterator.
- Wrap it in list() only when code needs a mutable list or a concrete list value.
What Is xrange() in Python?
Python 2.7 xrange() builds an immutable integer sequence for looping. The stop value is excluded. The optional start defaults to zero, and step defaults to one.
The Python 2.7 reference says xrange avoids storing every value and calls its advantage minuscule except on memory-starved systems or when a loop stops before using them all. Treat that as a storage benefit, not a promise of faster loops.
I keep the version split explicit because Python 2 and Python 3 give range() different concrete return types.
For example, list(range(2, 9, 2)) materializes [2, 4, 6, 8]. The returned list contains four mutable integers.
| Runtime and call | Result | Operations and use |
|---|---|---|
| Python 2 range() | List | Mutable list operations |
| Python 2 xrange() | Immutable sequence | Iteration, indexing and len() |
| Python 3 range() | Immutable sequence | __iter__(), __getitem__(), __len__(), slicing, membership and equality |
| Python 3 xrange() | NameError | Use range() |
Python calls these double-underscore methods through its sequence protocol. An iterable can provide an iterator, which tracks one traversal and supplies the next value when requested. A range object can be iterated over again, while an existing iterator continues from its current position.
For current usage examples of the built-in, see AskPython’s Python range() function guide. Its separate article on iterating through a range starting at 1 covers that common boundary choice.
How to Replace xrange() Step by Step
Start by preserving the old call’s arguments, then run a small check that exercises the same path.
Step 1: Run the old name to identify the Python version issue
Python 3 does not define xrange, so a call fails with NameError. In python3 xrange_migration_demo.py, I saw the error followed by Python 3 range and list values.
try:
xrange(4)
except NameError as error:
print(type(error).__name__, error)
print(list(range(4)))
print(list(range(2, 9, 2)))
print(list(range(9, 1, -1)))
print(type(range(4)).__name__)
print(type(list(range(4))).__name__)
values = range(2, 10, 2)
print(6 in values)
print(7 in values)
print(values[1])
print(values[1:3])
print(range(0, 3, 2) == range(0, 4, 2))
print(range(3) == [0, 1, 2])
for arguments in ((0, 5, 0), (0, 5.0)):
try:
range(*arguments)
except (TypeError, ValueError) as error:
print(type(error).__name__, error)
The command python3 xrange_migration_demo.py printed this output:
NameError name 'xrange' is not defined
[0, 1, 2, 3]
[2, 4, 6, 8]
[9, 8, 7, 6, 5, 4, 3, 2]
range
list
True
False
4
range(4, 8, 2)
True
False
ValueError range() arg 3 must not be zero
TypeError 'float' object cannot be interpreted as an integer
The first line shows the missing Python 2 name, then the lists show Python 3 replacements. The range and list type names differ. The remaining output checks sequence behavior and invalid arguments.
- Membership returns True for 6 and False for 7 in the stepped range.
- Indexing returns 4, and slicing returns range(4, 8, 2).
- Range objects representing the same values compare equal. A range and a list do not.
The final lines show the zero-step ValueError and float-boundary TypeError, with the exact messages Python printed.
The slice is displayed as range(4, 8, 2), a representation of the sequence rather than a printed list of its members. For a small range, list() can make each value visible during debugging. Avoid that conversion just to inspect a very large range, since it builds the full list in memory.

Step 2: Replace the call and retain its bounds
Keep the same start, stop and step when changing the spelling. For example, xrange(5, 20, 5) in Python 2 becomes range(5, 20, 5) in Python 3, yielding 5, 10 and 15. The next value would reach the excluded stop, so 20 does not appear.
Step 3: Convert only when the caller needs a list
Use list(range(…)) only when code needs mutable values, list-specific methods, or an API that requires a list.
When a loop needs both an index and a value from a collection, enumerate(collection) is often clearer than range(len(collection)). Use range when the numeric sequence itself drives the work, such as visiting every third index.
Python xrange() Errors and Edge Cases
A runtime name error differs from an invalid argument or an empty result. The table pairs each symptom with the correction that matches its cause.
| Case | Symptom | Fix |
|---|---|---|
| xrange(4) in Python 3 | NameError | Use range(4) |
| range(0, 5, 0) | ValueError from a zero step | Choose a non-zero step |
| range(0, 5.0) | TypeError for a float boundary | Pass an integer value |
| range(5, 2) | Empty sequence | Use a negative step to count down |
A positive step does not count backward when start is greater than stop. That call produces an empty sequence. The captured descending example used a negative step and returned values from 9 down to 2.
I keep the missing name separate from argument errors because the run produced different exception types.
The Python 2.7 built-in reference notes that CPython limits xrange arguments and element counts to native C longs. For sequences outside that limit, it points to an itertools alternative.
The current Python 3 range reference says values larger than sys.maxsize are allowed, though len() may raise OverflowError when the count cannot fit. A loop can still consume the values without requesting that length.
Conclusion
Seeing xrange() in a snippet tells you to check which Python version the author had in mind before running it.
The Python 2.7 built-in function reference documents the historical xrange behavior, while the Python 3 standard types reference describes range today. AskPython’s guides to range() and starting a range at one provide related examples.
FAQ
These short answers address common questions about the old name and its current replacement.
Does Python 3 have xrange()?
No. Python 3 removed the xrange name. Use range() for its lazy integer sequence behavior.
Do I need to import xrange in Python?
No import provides the removed Python 3 built-in. Replace xrange() with range() in Python 3 code.
Is Python 3 range() a list?
No. It returns an immutable range sequence. Use list(range(…)) when a mutable list is needed.


