Does range() return a list or a range object?

Why do we need to convert it to a list isn’t it already a list?
(if not then what is it?)

its not a list. Its a generator expression (not entirely, but close enough for now). Which hands you the values one by one rather then having all of numbers in memory (which a list does), so its more (memory) efficient.

Just to clarify, range() in Python 2 does return an object of type ‘list’,

>>> type (range(42))
<type 'list'>

unlike Python 3 which returns a range object.

>>> type (range(42))
<class 'range'>

The latter is a form of iterable that uses bounds, step and direction to know what the first value will be, and then the next, and the next, and so on until it has reached the other bound.

It is not an iterator, though, since it is not consumed in the process.

>>> a = range(10)
>>> for x in a: print (x, end='')
>>> for x in a: print (x, end='')

We see above that the range is unchanged. An iterator would not behave this way on the second or subsequent use. More on that later…

When we convert a range to a list (using the list constructor) the range is evaluated by the constructor and a list object is returned.

The nice thing about Python 3 range() is that it uses no more memory for a very large range than it would for a very small one.

Can you please elaborate “an iterator wouldn’t behave that way…”?

A range object is repeatedly iterable, which is not a property of iterators. The one thing that iterators have in common is that they are consumed on the first pass.

The big difference under the hood is that range has a defined __iter__() method, whereas iterators have a defined, next() method, which iterables do not. When the next method is invoked, it consumes the next value, thereby eventually consuming the entire object.

Take for example the zip() object.

>>> a = range(1, 27)
>>> b = map(lambda x: chr(x), range(97, 124))
>>> c = zip(a, b)
>>> d = {m: n for m, n in c}
>>> d
{1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g', 8: 'h', 9: 'i', 10: 'j', 11: 'k', 12: 'l', 13: 'm', 14: 'n', 15: 'o', 16: 'p', 17: 'q', 18: 'r', 19: 's', 20: 't', 21: 'u', 22: 'v', 23: 'w', 24: 'x', 25: 'y', 26: 'z'}
>>> list(c)

Notice how the zip object, c is now empty?

1 Like

thanks for giving me a heads up! i also researched some of it and now everything makes sense.

1 Like

Allow me to add here this excerpt from the python docs:

The advantage of the range type over a regular list or tuple is that a range object will always take the same (small) amount of memory, no matter the size of the range it represents (as it only stores the start , stop and step values, calculating individual items and subranges as needed).