range vs. xrange in Python
Python has a built-in function called range that can easily generate a range of whole numbers. There is another built-in function called xrange that provides the same result, but uses a lot less memory.
range and xrange
In the following 3 examples we could replace range by xrange and receive the same result:
examples/python/range_3_7.py
#!/usr/bin/env python from __future__ import print_function for v in range(3, 7): print(v)
From the first number (3) until one less than the second number (7):
3 4 5 6
examples/python/range_5.py
#!/usr/bin/env python from __future__ import print_function for v in range(5): print(v)
If there is only one number, that will be the end number and the default start number will be 0. Thus range(5) is the same as range(0, 5)
0 1 2 3 4
examples/python/range_step.py
#!/usr/bin/env python from __future__ import print_function for v in range(0, 5, 2): print(v)
If there are three parameters, the third one is the "step" that defaults to 1 if the third parameter is not present. The result will be the following:
0 2 4
Variable holding a range
What if we would like to create a variable that will hold the range? We can do that and it is quite simple with either range or xrange
r = range(1000)
Then we can go over the elements:
for v in r: pass
or we can access them by index:
print(r[4])
Memory Size
The big difference is in the amount of memory they use:
examples/python/range-memory.py
#!/usr/bin/env python from __future__ import print_function import sys r = range(10000) print(sys.getsizeof(r)) # 80072 x = xrange(10000) print(sys.getsizeof(x)) # 40
The variable holding the range created by range uses 80072 bytes while the variable created by xrange only uses 40 bytes.
The reason is that range creates a list holding all the values while xrange creates an object that can iterate over the numbers on demand.
examples/python/range-type.py
#!/usr/bin/env python from __future__ import print_function import sys r = range(10000) x = xrange(10000) print(type(r)) # <type 'list'> print(type(x)) # <type 'xrange'>
Speed - Benchmarking range and xrange
The "cost" of the memory savings is that looking up indexes in xrange will take slightly longer. This benchmark code uses the timeit module to show that the xrange version is 10% slower:
examples/python/range-benchmark.py
#!/usr/bin/env python from __future__ import print_function import timeit r = range(10000) x = xrange(10000) def range_index(): z = r[9999] def range_xindex(): z = x[9999] if __name__ == '__main__': import timeit print(timeit.timeit("range_index()", setup="from __main__ import range_index", number=10000000)) print(timeit.timeit("range_xindex()", setup="from __main__ import range_xindex", number=10000000))
The resulting numbers are:
2.16770005226 2.35304307938
Published on 2015-06-25