"
Last Updated: Thursday 27th January 2022

## What is Python's range() Function?

As an experienced Python developer, or even a beginner, you've likely heard of the Python `range()` function. But what does it do? In a nutshell, it generates a list of numbers, which is generally used to iterate over with `for` loops. There's many use cases. Often you will want to use this when you want to perform an action X number of times, where you may or may not care about the index. Other times you may want to iterate over a list (or another iterable object), while being able to have the index available.

The `range()` function works a little bit differently between Python 2.x and 3.x under the hood, however the concept is the same. We'll get to that a bit later, however.

## Python's range() Parameters

The `range()` function has two sets of parameters, as follows:

`range(stop)`

• `stop`: Number of integers (whole numbers) to generate, starting from zero. eg. `range(3) == [0, 1, 2]`.

`range([start], stop[, step])`

• `start`: Starting number of the sequence.
• `stop`: Generate numbers up to, but not including this number.
• `step`: Difference between each number in the sequence.

Note that:

• All parameters must be integers.
• All parameters can be positive or negative.
• `range()` (and Python in general) is 0-index based, meaning list indexes start at 0, not 1. eg. The syntax to access the first element of a list is `mylist[0]`. Therefore the last integer generated by `range()` is up to, but not including, `stop`. For example `range(0, 5)` generates integers from 0 up to, but not including, 5.

## Python's range() Function Examples

#### Simple Usage

[python]
>>> # One parameter
>>> for i in range(5):
... print(i)
...
0
1
2
3
4
>>> # Two parameters
>>> for i in range(3, 6):
... print(i)
...
3
4
5
>>> # Three parameters
>>> for i in range(4, 10, 2):
... print(i)
...
4
6
8
>>> # Going backwards
>>> for i in range(0, -10, -2):
... print(i)
...
0
-2
-4
-6
-8
[/python]

#### Iterating Lists

[python]
>>> my_list = ['one', 'two', 'three', 'four', 'five']
>>> my_list_len = len(my_list)
>>> for i in range(0, my_list_len):
... print(my_list[i])
...
one
two
three
four
five
[/python]

#### 99 Bottles of Beer on the Wall...

With the following code:
[python]
for i in range(99, 0, -1):
if i == 1:
print('1 bottle of beer on the wall, 1 bottle of beer!')
print('So take it down, pass it around, no more bottles of beer on the wall!')
elif i == 2:
print('2 more bottles of beer on the wall, 2 more bottles of beer!')
print('So take one down, pass it around, 1 more bottle of beer on the wall!')
else:
print('{0} bottles of beer on the wall, {0} bottles of beer!'.format(i))
print('So take it down, pass it around, {0} more bottles of beer on the wall!'.format(i - 1))
[/python]

We get the following output:

[python]
99 bottles of beer on the wall, 99 bottles of beer!
So take one down, pass it around, 98 more bottles of beer on the wall!
98 bottles of beer on the wall, 98 bottles of beer!
So take one down, pass it around, 97 more bottles of beer on the wall!
97 bottles of beer on the wall, 97 bottles of beer!
So take one down, pass it around, 96 more bottles of beer on the wall!
...
3 bottles of beer on the wall, 3 bottles of beer!
So take one down, pass it around, 2 more bottles of beer on the wall!
2 more bottles of beer on the wall, 2 more bottles of beer!
So take one down, pass it around, 1 more bottle of beer on the wall!
1 bottle of beer on the wall, 1 bottle of beer!
So take it down, pass it around, no more bottles of beer on the wall!
[/python]

Brilliant! Finally you can see the true power of Python :). If you're a little confused, for reference see the Wikipedia article.

## Python's range() vs xrange() Functions

You may have heard of a function known as `xrange()`. This is a function that is present in Python 2.x, however it was renamed to `range()` in Python 3.x, and the original `range()` function was deprecated in Python 3.x. So what's the difference? Well, in Python 2.x `range()` produced a list, and `xrange()` returned an iterator - a sequence object. We can see this in the following example:

[python]
>>> range(1)
range(0, 1)
>>> type(range(1))

[/python]

[python]
>>> range(1)
[0]
>>> type(range(1))

[/python]

So in Python 3.x, the `range()` function got its own `type`. In basic terms, if you want to use `range()` in a `for` loop, then you're good to go. However you can't use it purely as a `list` object. For example you cannot slice a `range` type.

When you're using an iterator, every loop of the `for` statement produces the next number on the fly. Whereas the original `range()` function produced all numbers instantaneously, before the `for` loop started executing. The problem with the original `range()` function was that it used a very large amount of memory when producing a lot of numbers. However it tends to be quicker with a small amount of numbers. Note that in Python 3.x, you can still produce a list by passing the generator returned to the `list()` function. As follows:

[python]
>>> list_of_ints = list(range(3))
>>> list_of_ints
[0, 1, 2]
[/python]

## Using floats with Python's range() function

Unfortunately the `range()` function doesn't support the `float` type. However don't get upset too soon! We can easily implement it with a function. There's several ways it can be done, however here's one.

[python]
>>> # Note: All arguments are required.
>>> # We're not fancy enough to implement all.
>>> def frange(start, stop, step):
... i = start
... while i < stop: ... yield i ... i += step ... >>> for i in frange(0.5, 1.0, 0.1):
... print(i)
...
0.5
0.6
0.7
0.8
0.9
1.0
[/python]

Brilliant!