If range() and xrange() were implemented in the Python language, they would look something like this:
def xrange(start, stop=None, step=1):
if stop is None: stop, start = start, 0
i = start
while i < stop:
yield i
i += step
def range(start, stop=None, step=1):
if stop is None: stop, start = start, 0
acc, i = [], start
while i < stop:
acc.append(i)
i += step
return acc
As you can see, range() creates a list and returns it, while xrange() lazily generates the values in a range on demand. This has the advantage that the overhead for creating a list is avoided in xrange(), since it doesn't store the values or create a list object. For most instances, there is no difference in the end result.
One obvious difference is that xrange() doesn't support slicing:
>>> range(10)[2:5]
[2, 3, 4]
>>> xrange(10)[2:5]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: sequence index must be integer, not 'slice'
>>>
It does, however support indexing:
>>> xrange(11)[10]
10
map()andfilter()but with a syntax which is usually significantly more readable.