Why does range () not return a list?

I ran into some problems when using the range() function to create list s.
By doing some experiments, I get the following:

 >>> isinstance([], list) True >>> isinstance(range(10), list) False 

Also, after reading his documentation:

 >>> print(range.__doc__) range(stop) -> range object range(start, stop[, step]) -> range object Return a virtual sequence of numbers from start to stop by step. 

I currently have a workaround using list(range()) , but the question still remains. What is a virtual sequence of numbers?

+6
source share
1 answer
An object

A range() calculates numbers on demand, for example. when repeating or trying to access certain indices:

 >>> r = range(2, 80, 3) >>> len(r) 26 >>> r[15] 47 >>> 42 in r False >>> r[:10] range(2, 32, 3) 

This is a sequence because the object supports membership testing, indexing, slicing, and has length, just like a list or tuple. But, unlike a list or tuple, it actually does not contain integers in a sequence in memory, making it virtual.

When you call list() on a range() object, you create a new sequence containing all the integers that are in the range, but now you save all these integers:

 >>> r_list = list(r) >>> r_list [2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 77] 

This is also a sequence, but it takes up more memory, since all integers are now created in front, and you will use them or not. Thus, a list or tuple is a specific sequence.

Using the sys.getsizeof() function, we can calculate how much memory each object uses:

 >>> import sys >>> sys.getsizeof(r) 48 >>> sys.getsizeof(r_list) + sum(sys.getsizeof(i) for i in r_list) 1072 

The list object uses 22 times memory; because it contains 26 whole objects.

To answer the comment on your question, range() objects are not iterators . Iterators produce values ​​one by one on demand, but cannot be indexed, they produce all values ​​only once, and they cannot be indexed. You can create an iterator from a range() object using the iter() function:

 >>> iter(r) <range_iterator object at 0x10aea23f0> >>> r_iter = iter(r) >>> len(r_iter) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: object of type 'range_iterator' has no len() >>> list(r_iter) [2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 77] >>> list(r_iter) [] 

but after exhaustion, the iterator will not play the same range again.

All of the above applies mainly to Python 3; in Python 2, the type is called xrange() , where it is more limited in its capabilities (it does not support slicing and can process integers < sys.maxint ).

+17
source

Source: https://habr.com/ru/post/979875/


All Articles