1

I don't understand why the map object flushes itself(if that's what it is doing).

Here is what I tried.

>>> squares = map(lambda x: x**2, range(10))
>>> squares
<map object at 0x7f25a1cae2e8>
>>> square_list = list(squares)
>>> square_list
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> list(squares)
[]

Why is it empty? Same again for below

>>> squares = map(lambda x: x**2, range(10))
>>> squares
<map object at 0x7f25a1cae320>
>>> [x for x in list(squares)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> list(squares)
[]
>>> squares
<map object at 0x7f25a1cae320>
>>> 
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
Tasdik Rahman
  • 2,160
  • 1
  • 25
  • 37

3 Answers3

2

In Python 3.x, map doesn't return a list object, instead it returns an iterator.

Return an iterator that applies function to every item of iterable, yielding the results.

Basically, it doesn't process all the elements of the iterable passed immediately. It just processes one at a time, whenever asked for it.

In your case, all the elements from the range objects are processed one by one and when all of them are processed, the iterator object returned by map is exhausted (there is nothing else left to be processed). That is why you are getting empty list, when you do list(squares) the second time.

For example,

>>> squares = map(lambda x: x**2, range(10))
>>> next(squares)
0
>>> next(squares)
1
>>> next(squares)
4
>>> next(squares)
9

here, we have just processed the first four items, on demand. The values were not calculated before-hand, but the lambda function is called with the next value from the iterator passed to squares (range(10)), when you actually did next(squares) and the value is returned.

>>> list(squares)
[16, 25, 36, 49, 64, 81]

now, only the rest of the items in the iterator are processed. If you try to get the next item,

>>> next(squares)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
StopIteration

since the squares is exhausted, StopIteration is raised and that is why list(squares) is not getting any elements to process and returns an empty list.

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
1

It's covered here, here, here, and here

"In Python 3+, many processes that iterate over iterables return iterators themselves. In most cases, this ends up saving memory, and should make things go faster. " - user Triptych

jDo
  • 3,962
  • 1
  • 11
  • 30
  • But how does that explain the empty list being returned? – Tasdik Rahman Mar 09 '16 at 06:30
  • Generator functions are efficient memory-wise precisely for this reason. They do not store all the values generated in memory. Instead, a single value/iteration is generated and returned each time you call next() or use it in an iterative loop. If you want to keep the list, you have to assign it to a variable during the first - and only - round of iterations like so `squares_list = list(squares)`. Makes sense? – jDo Mar 09 '16 at 06:43
  • Yes. Thanks for explaining :) – Tasdik Rahman Mar 09 '16 at 07:11
-1

@thefourtheye and @jDo have explained it all. if you dont want your "squares" object to be flushed ,make it a list by :

squares = list(map(lambda x: x**2, range(10)))

So, now every time you want to use squares element,you can use it.

nsr
  • 855
  • 7
  • 10