This tutorial explains what is Python Range function and how to use it in your programs. Also learn the differences between range() and xrange():
A range is a close interval between two points. We use ranges everywhere i.e. from the 1st to 31st, from August to December, or from 10 to 15. Ranges help us to enclose a group of numbers, letters, etc which we can use later for different needs.
In Python, there is an inbuilt function called range() that returns an object that produces a sequence of numbers(integers) that will be later on used in our program.
=> Check ALL Python Tutorials Here
What You Will Learn:
The Python range() Function
The range() function returns a generator object that can produce a sequence of integers.
In this section, we will discuss the Python range() function and its syntax. Before we delve into the section, it is important to note that Python 2.x has 2 types of range functions i.e. the xrange() and the range(). Both of them are called and used in the same way but with different output.
The range() was dropped and xrange() was re-implemented in Python 3.x and named range(). We will get into xrange() later on and for now we will focus on range().
The Python range() Syntax
As mentioned before, a range is a sequence of integers between 2 endpoints.
To get the syntax of range, we can look at its docstring from the terminal with the below command:
>>> range.__doc__ 'range(stop) -> range object\nrange(start, stop[, step]) -> range object\n\nReturn an object that produces a sequence of integers from start (inclusive)\nto stop (exclusive) by step. range(i, j) produces i, i+1, i+2, ..., j-1.\nstart defaults to 0, and stop is omitted! range(4) produces 0, 1, 2, 3.\nThese are exactly the valid indexes for a list of 4 elements.\nWhen step is given, it specifies the increment (or decrement).'
Notice the first line
range(stop) -> range object\nrange(start, stop[, step]) -> range
Different Ways to Construct Range
The above syntax shows that the range() function can take up to 3 parameters.
This provides Python range() syntax with about 3 different ways of implementation as shown below.
NB: We should note the following default values for the different parameters.
- start defaults to 0
- step defaults to 1
- stop is required.
#1) range(stop)
As seen above, the range function takes a stop parameter(exclusive) which is an integer that indicates where the range will end. Therefore if you use range(7), it will display all the integers from 0 to 6.
In a nutshell, whenever the range() is given a single argument, that argument represents the stop parameter, and the start and step parameters adopt their default values.
Example 1: Print a range of integers from 0 to 6.
>>> list(range(7)) [0, 1, 2, 3, 4, 5, 6]
#2) range(start, stop)
Here, the range() function is called with two parameters (start and stop). These parameters can be any integer where the start is greater than stop (start > stop). The first parameter (start) is the starting point of the range and the other parameter(stop) is the exclusive end of the range.
NB: The stop parameter is exclusive. For example, range(5,10) will result in a sequence from 5 to 9, excluding 10.
Example 2: Find the range between two numbers, where start=5 and stop=10
>>> list(range(5,10)) [5, 6, 7, 8, 9]
#3) range(start, stop, step)
Here, when the range() receives 3 arguments, the arguments represent the start, stop and step parameters from left to right.
When the sequence of numbers is created, the first number will be the start argument, and the last number of the sequence will be a number before the stop argument, represented as a stop – 1.
The step argument indicates how many “steps” will separate each number in the sequence. It could be incremental or decremental steps.
We should recall that by default, the step parameter defaults to 1. So, if by any chance we want it to be a 1, then we can decide to provide it explicitly or omit it.
NB: The step argument can’t be 0 or a floating-point number.
Consider the example below where start=5, stop=15, and step=3
Example 3: Find a range of sequence from 5 to 14, having an increment of 3
>>> list(range(5,15,3)) [5, 8, 11, 14]
Using Negative steps with range()
The step parameter of the range() function can be a negative integer that is range(30, 5, -5). As seen in the below figure, when using a negative step, the start parameter has to be higher than the stop parameter. If not, the resulting sequence will be empty.
The counter will count from the start while using the step to jump over to the next value.
Example 4: Let’s see how a negative step works when the start is greater or smaller than the stop.
>>> list(range(30,5,-5)) # start > stop [30, 25, 20, 15, 10] >>> list(range(5,30,-5)) # start < stop []
How to Use Python range()
The range has its place in Python and it is often used in many programs. In this section, we shall exploit some of the ways in which it can be used.
Using Python range() in Loops
The for loop is one of the most common areas where range() is used. A for loop statement is the one that iterates through a collection of items. To learn more about Python loops and the for loop, read through the tutorial Loops in Python.
Example 5: Using a for loop and range(), print a sequence of numbers from 0 to 9.
def rangeOfn(n): for i in range(n): print(i) if __name__ == '__main__': n = 10 rangeOfn(n)
Output
Example 5 given above uses the range(stop) syntax. This returns a generator object which is fed into the for loop, which iterates through the object, extracting the items and printing them.
Example 6: Using a for loop and range(), print a sequence of numbers from 5 to 9.
This example uses the range(start, stop) syntax, where the start will define where the loop will begin(Inclusive) and the stop where the loop will end(stop-1)
def rangeFromStartToStop(start, stop): for i in range(start, stop): print(i) if __name__ == '__main__': start = 5 # define our start value stop = 10 # define our stop value rangeFromStartToStop(start, stop)
Output
Example 7: Using a for loop and range(), print a sequence of numbers from 5 to 9 and an increment of 2.
This example uses the range(start, stop, step) syntax in the for statement. The for statement will begin the count at the start parameter and will jump to the next value according to the step integer and will end at stop-1.
def rangeFromStartToStopWithStep(start, stop, step): for i in range(start, stop, step): print(i) if __name__ == '__main__': start = 5 # define our start value stop = 10 # define our stop value step = 2 # define our increment rangeFromStartToStopWithStep(start, stop, step)
Output
For our last example in this section, we shall look at how iterables are commonly iterated. Consider the example below.
Example 8: Iterate through the list [3,2,4,5,7,8] and print all its items.
def listItems(myList): # use len() to get the length of the list # the length of the list represents the 'stop' argument for i in range(len(myList)): print(myList[i]) if __name__ == '__main__': myList = [3,2,4,5,7,8] # define our list listItems(myList)
Output
Using range() with Data Structures
As we mentioned earlier in this tutorial, the range() function returns an object (of type range) that produces a sequence of integers from start (inclusive) to stop (exclusive) by step.
Hence, running the range() function on its own will return a range object which is iterable. This object can easily be converted into various data structures like List, Tuple, and Set as shown below.
Example 9: Construct a list with a sequence of integers from 4 to 60 (inclusive), and an increment of 4.
>>> list(range(4, 61, 4)) # our 'stop' argument is 61 because 60 is inclusive. [4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60]
From example 9 above, all we had to do is call our range function in the list() constructor.
Example 10: Construct a tuple with a sequence of integers from 4 to 60 (inclusive), and an increment of 4.
>>> tuple(range(4, 61, 4)) # enclose in the tuple() constructor (4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60)
Example 11: Construct a set with a sequence of integers from 4 to 60 (inclusive) and an increment of 4.
>>> set(range(4, 61, 4)) # enclose in the set() constructor {32, 4, 36, 8, 40, 12, 44, 60, 16, 48, 20, 52, 24, 56, 28}
NB: Notice how the resulting sequence of integers is unordered. This is because a set is an unordered collection.
This example 11 may seem useless at first since the range object will always return a sequence of unique integers. So, we may ask ourselves, why enclosing in a set() constructor. Well, imagine that you need to have a default set containing a sequence of integers in which you will later add some items.
Python xrange()
As mentioned before xrange() is a Python 2.x function which acts as the range() function in the 3.x Python version. The only similarity between these two functions is that they produce a sequence of numbers and can use the start, stop, and step parameters.
It is important to know that, in Python 2.x, both range() and xrange() are defined, where range() returns a list object while xrange() returns a range object. However, migrating to Python 3.x, the range was dissolved and xrange was re-implemented and named range.
Example 12: Return value of range and xrange in Python 2.x
>>> xr = xrange(1,4) >>> xr # output the object created xrange(1, 4) >>> type(xr) # get type of object <type 'xrange'> >>> r = range(1,4) >>> r # output the object created [1, 2, 3] >>> type(r) # get type of object <type 'list'>
Difference Between range() And xrange()
In this section, we shall not look much at the difference between xrange() and range() in Python 2.x. However, we shall look at the difference between xrange() of Python 2.x and range() of Python 3.x.
Though xrange() was re-implemented in Python 3.x as range(), it added some features to it and that made it different from its predecessor.
The differences between range() and xrange() can be related to operational differences, memory consumption, returned type, and performance. But in this section, we shall look at the operational differences and memory consumption.
NB:
- Code in this section will be run on the Python shell terminal. Given that we have both Python 2 and 3 installed, we can access Python 2 shell with the command.
python2
Python 3 shell terminal with the command.
python3
- All code related to xrange should be run on the Python 2 shell while all code related to the range should be run on the Python 3 shell.
#1) Operational Differences
xrange and range operate the same way. They both have the same syntax and return objects that can produce sequences of integers.
Example 13: Operational difference between xrange and range
Solution 13.1: Python 3.x
>>> r = range(3,8,2) # create range >>> r range(3, 8, 2) >>> type(r) # get type <class 'range'> >>> list(r) # convert to list [3, 5, 7] >>> it = iter(r) # get iterator >>> next(it) # get next 3 >>> next(it) # get next 5
Solution 13.2: Python 2.x
>>> xr = xrange(3,8,2) # create xrange >>> xr # notice how it is represented below with 9 instead of 8. xrange(3, 9, 2) >>> type(xr) # get type. Here it is of type 'xrange' <type 'xrange'> >>> list(xr) # get list [3, 5, 7] >>> it = iter(xr) # get iterator >>> it.next() # get next 3 >>> next(it) # get next 5
From the solutions above, we see that the types are named differently. Also, the stop argument is incremented for xrange. Both can return an iterator from iter() but the iter built-in next() method works only for xrange while both support the built-in next() function.
In this scenario, both operate precisely in the same way. However, we have some list operations that can apply to the range but not on xrange. Recall that Python 2.x had both xrange and range but the range here was of the type list.
So, while migrating to Python 3.x, xrange was re-implemented and some of the range properties were added to it.
Example 14: Check if xrange and range support indexing and slicing.
Solution 14.1: Python 3.x
>>> r = range(3,8,2) # create range >>> r # print object range(3, 8, 2) >>> list(r) # return list of object [3, 5, 7] >>> r[0] # indexing, returns an integer 3 >>> r[1:] # slicing, returns a range object range(5, 9, 2) >>> list(r[1:]) # get list of the sliced object [5, 7]
Solution 14.2: Python 2.x
>>> xr = xrange(3,8,2) # create xrange >>> xr # print object xrange(3, 9, 2) >>> list(xr) # get list of object [3, 5, 7] >>> xr[0] # indexing, return integer 3 >>> xr[1:] # slicing, doesn't work Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: sequence index must be integer, not 'slice'
We can conclude that xrange doesn’t support slicing.
#2) Memory Consumption
Both xrange and range have static memory storage for their objects. However, xrange consumes less memory than range.
Example 15: Check the memory consumed by both xrange as well as range.
Solution 15.1: Python 3.x
>>> import sys # import sys module >>> r = range(3,8,2) # create our range >>> sys.getsizeof(r) # get memory occupied by object 48 >>> r2 = range(1,3000000) # create a wider range >>> sys.getsizeof(r2) # get memory, still the same 48
Solution 15.2: Python 2.x
>>> import sys >>> xr = xrange(3,8,2) >>> sys.getsizeof(xr) # get memory size 40 >>> xr2 = xrange(1, 3000000) # create wider range >>> sys.getsizeof(xr2) # get memory 40
We see that xrange objects occupy a memory size of 40, unlike a range that occupies 48.
range() in Numpy
Numpy is a Python library for numerical computation. Numpy provides a variety of methods to create arrays in which the arange() function is a part.
Installation
We can first check if Numpy is already installed in our system by running the below command.
>>> Import numpy
If we get the ModuleNotFoundError exception, then we have to get it installed. One way is to use pip as shown below;
>>> pip install numpy
Syntax
numpy.arange([start, ]stop, [step, ]dtype=None) -> numpy.ndarray
From the syntax above, we see the similarity with the Python range(). But in addition to this parameter, the Python arange() also gets the dtype which defines the type of the return array.
Also, it returns a numpy.ndarray rather than a decorator object like Python range().
Example 16: Check returned type of numpy.arange()
>>> import numpy as np # import numpy >>> nr = np.arange(3) # create numpy range >>> nr # display output, looks like an array array([0, 1, 2]) >>> type(nr) # check type <class 'numpy.ndarray'>
The four parameters in arange() are the data type (dtype) which define the numeric built-in value in the return array. The dtypes offered by numpy differs in memory used and have limits as seen in the table below.
Table on numpy data types (dtype)
Date Type (dtype) | Description |
---|---|
np.int8 | 8-bit integer Range from -128 to 127 |
np.unit8 | 8-bit unsigned integer Range from 0 to 255 |
np.int16 | 16-bit integer Range from 32768 to 32767 |
np.unit16 | 16-bit unsigned integer Range from 0 to 65535 |
np.int32 | 32-bit integer Range from -2**31 to 2**31-1 |
np.unit32 | 32-bit unsigned integer Range from 0 to 2**32-1 |
np.int64 | 64-bit integer Range from -2**63 to 2**63-1 |
np.unit64 | 64-bit unsigned integer Range from 0 to 2**64-1 |
Example 17: Using dtype of 8bits integer
>>> import numpy as np >>> x = np.arange(2.0, 16, 4, dtype=np.int8) # start is float >>> x # but output is int8 stated by dtype array([ 2, 6, 10, 14], dtype=int8) >>> x.dtype # check dtype dtype('int8')
If dtype is not assigned, then the dtype of the resulting array will be determined based on the step, stop and step arguments.
If all the arguments are integers, then the dtype will be int64. However, if the data type changes to the floating-point in any of the arguments, then the dtype will be float64.
Difference Between numpy.arange() And range()
- range() is a built-in Python class while numpy.arange() is a function that belongs to the Numpy library.
- Both collect the start, stop and step parameters. The only difference comes in when the dtype is defined in the numpy.arange() thereby making it able to use 4 parameters while range() uses only 3.
- The return types are different: range() returns a Python class range while numpy.arange() returns an instance of Numpy ndarray. These return types are better than each other depending on the situations they are required in.
- numpy.arange() supports floating-point numbers for all its parameters while range supports only integers.
Before we round up this section, it is important to know that as numpy.arange doesn’t return a decorator object like range(), it has a limitation in the range of sequence it can generate.
Example 18: Show numpy.arange limitation
NB: Please don’t try this, or it may take forever to run or just crash your system.
>>> np.arange(1, 90000000000)
Frequently Asked Questions
Q #1) How to turn a range() to a list in Python3
Answer: To change a range to a list in Python 3.x you will just need to call a list encapsulating the range function as below.
>>> list(range(4,16,2)) [4, 6, 8, 10, 12, 14]
Q #2) How does the Python range work?
Answer: Basically, Python range takes in three parameters namely i.e. start, stop and step and creates a sequence of integers starting from the start, ending at stop-1 and incremented or decremented by step.
Python range() works differently based on the Python version. In Python 2.x, range() returns a list while in Python 3.x, a range object is returned.
Q #3) Explain the Error “xrange not defined” while running in python3.
Answer: This error occurs because xrange() is not a built-in function in Python 3.x. The xrange() function is instead built-in in Python 2.x but was re-implemented in Python 3.x and named range.
Conclusion
In this tutorial, we looked at Python range() and its syntax. We examined the different ways in which we can construct a range based on the number of parameters provided. We also looked at how Python range() is used in a loop like for loop and data structures like list, tuple, and set.
Down the line, we looked at the differences between xrange in Python 2.x and range in Python 3.x. Finally, we had a glance at how the range is implemented in Numpy.
=> Visit Here To Learn Python From Scratch