5
What is the function for range()
in Python? What is its real use? It’s just a numerical list?
5
What is the function for range()
in Python? What is its real use? It’s just a numerical list?
11
The range
is an eternal class. It is somewhat similar to a list, but unlike a list itself, the intermediate values are not stored in memory, and are then calculated as it is iterated based on the value of the step
(which by default is 1). Thus, a range with an element and a range with a million elements use the same amount of memory, which translates into space savings and better performance.
An example of use:
for i in range(1, 10):
print(i)
This example shows the numbers from 1 to 9. The first parameter, which is called start
is the first number inside the range
. The second parameter, called stop
is the first number that nay is more in the sequence. The number 10 does not appear in the sequence because it is no longer inside the range
, and so that goes from 1 to 9.
It is also possible to specify the value of the step
when using a third parameter:
for i in range(1, 10, 2):
print(i)
This will then show the numbers 1, 3, 5, 7 and 9. That is, skipping 2 in 2.
If only one parameter is specified, this will be the stop
and the value 0 shall be assumed for the start
. Thus, range(5)
corresponds to the numbers from 0 to 4.
The range
can also be accessed at arbitrary positions without intermediate values needing to be calculated (for example, range(1, 10)[3]
). The resulting value (for positive indices within the range) is easily obtained by means of the formula start + index * step
.
6
In Python 3, range
, despite being used as a function, including the initial examples of tutorials in Python, is not a function. It is a class:
In [1]: teste = range(10)
In [2]: type(teste)
Out[2]: range
In [3]: type(range)
Out[3]: type
In [4]: isinstance(range, type)
Out[4]: True
range
is a class and the objects that are instances of that class, which we can call "ranges" have all the properties of Immutable Sequences in Python.
In Python 2, range
was a function, which returned a list (list
), python normal:
Python 2.7.15 (default, Oct 15 2018, 15:26:09)
...
In [1]: teste = range(10)
In [2]: type(teste)
Out[2]: list
In [3]: type(range)
Out[3]: builtin_function_or_method
In [4]: isinstance(range, type)
Out[4]: False
What happens is that at some point it has been found that very rare, if ever, when a numerical sequence is needed you will need to have all the numbers of a sequence at once in memory - as you go through the sequence, you will use one number at a time. So still in Python 2 they created the xrange
that it was this specialized class to "look like a function", whose return "behaves like a list", but it is in the verdad a sequence "virtual".
The call a range in Python 3 also does not return an "iterator" in Python is something different - it is an object that provides items in sequence, and which can, for example, be consumed by the command for
, but can be run only once. If you try to use the same iterator more than once, in the second use it will be empty.
So the "range" object, as well as the lists, tuples and other sequences is an "iterable": I mean - you can build iterators with it, as many times as you want, and each iterator will generate all the elements independently. The command for
creates an iterator from an iterable automatically, but this can also be done explicitly with built-in iter
:
In [6]: print([i for i in teste])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [7]: print([i for i in teste])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [8]: t2 = iter(teste)
In [9]: print([i for i in t2])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [10]: print([i for i in t2])
[]
And deep down, despite the class range
be defined in C, the Python equivalent of it is very simple. What the call a range returns is an instance of a class equivalent to this one:
class Range:
def __init__(self, start, stop=None, step=1):
if stop is None:
stop = start
start = 0
self.start = start
self.stop = stop
self.step = step
def __len__(self):
return (self.start - self.stop) // self.step
def __getitem__(self, index):
if index < 0:
index += len(self)
result = self.start + self.step * index
if index < 0 or result >= self.stop:
raise IndexError
return result
def __iter__(self):
i = 0
while True:
try:
yield self[i]
except IndexError:
break
i += 1
Ready!
The whole "secret" to calculate a number at a Range position at the time it is requested, without going through the previous ones, is the formula result = self.start + self.step * index
.
One interesting thing that is clear in this recreation is the part of the range that is very intuitive to use, but can give a headache when we stop to think: the range
Python when called with two parameters uses the first as the beginning and the second as the end. But when called only with a parameter, instead of using this parameter as "start" and leaving the end undefined, it takes the beginning as "0", which makes a lot of sense, and puts the only parameter as the "end".
So it’s possible to do range(10)
for numbers from 0 to 10, and range(5, 10)
, for numbers between 5 and 10.
In this class is not implemented the logic to allow regressive counts with negative indices - but just add different checks on __getitem__
when the self.step
for negative - I chose to make the code easier to read. On the other hand as I also do not check the types of the parameters, this class works for floating point numbers as well as for integers:
In [21]: a = Range(0, 2, 0.25)
In [22]: print([i for i in a])
[0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75]
It is worth noting that when implementing the special method __iter__
as a Generator (that is: with a yield
), the class becomes "eternal", as I described in the beginning. In each for
that an instance of this class Range
is used, Python will call __iter__
, and have a generator, which will count all available numbers and "expire".
Browser other questions tagged python python-3.x
You are not signed in. Login or sign up in order to post.
Good to remember that the mathematical notation of the Range is:
range([start], stop[, step])
.– Fabricio Paiva
This is not mathematical notation; I believe you meant the signature of the function. And the correct would be
range(stop)
orrange(start, stop[, step])
. Right?– Woss
Related: How can you check if number is in range be so fast?
– Woss
The notation of the intervals. In fact you’re right...although brackets represent intervals too, the most common in mathematics is to use the line of the real ones.
– Fabricio Paiva
In this case it would be
α ∈ [start, stop[ ∀ α = start + k*step, k ∈ N
just. In response it seemed that you ended up mixing things up– Woss