31

Why doesn't following code print anything:

#!/usr/bin/python3
class test:
    def do_someting(self,value):
        print(value)
        return value

    def fun1(self):
        map(self.do_someting,range(10))

if __name__=="__main__":
    t = test()
    t.fun1()

I'm executing the above code in Python 3. I think i'm missing something very basic but not able to figure it out.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Sibi
  • 47,472
  • 16
  • 95
  • 163

3 Answers3

66

map() returns an iterator, and will not process elements until you ask it to.

Turn it into a list to force all elements to be processed:

list(map(self.do_someting,range(10)))

or use collections.deque() with the length set to 0 to not produce a list if you don't need the map output:

from collections import deque

deque(map(self.do_someting, range(10)))

but note that simply using a for loop is far more readable for any future maintainers of your code:

for i in range(10):
    self.do_someting(i)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 5
    Also, the OP may just be missing a `return`, but it's generally not considered good practice to use `map` to execute a function repeatedly for side-effects (in this case `print`) as opposed to working with the result set... – Jon Clements Nov 29 '12 at 10:33
  • 3
    @JonClements: The OP is playing around with the map function and created a short piece of example code to show that things didn't work as he expected, I'd say. – Martijn Pieters Nov 29 '12 at 10:35
  • 6
    Creating a temporary list is not the best thing, I'd say. The **`consume` [recipe](http://docs.python.org/3/library/itertools.html#itertools-recipes)** may be better. – Oleh Prypin Nov 29 '12 at 10:45
  • 2
    Note that creating a `collection.deque` with `maxlen=0` is equivalent to calling `itertools.consume`. The latter, however, is much more readable to me since it is clear that you want to consume the iterator. – ruancomelli Apr 18 '20 at 18:07
  • @rugortal there is no `itertools.consume()`. There is a `consume()` example function definition in the [`itertools` documentation recipes section](https://docs.python.org/3/library/itertools.html#itertools-recipes), but that’s not part of what the module provides. – Martijn Pieters Apr 19 '20 at 01:03
  • @MartijnPieters, you're right, thanks for pointing that out. I got confused because, while a recipe for `consume` indeed exists in `itertools`, they do not provide such function. Instead, one can find `consume` implemented in [more-itertools](https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.consume). – ruancomelli Apr 19 '20 at 14:15
  • 1
    `for` loops are better for smaller code blocks. i personally prefer a functional approach with `map` calls, and dividing code into smaller chunks when the instruction set gets large. i highly recommend this book on the subject: https://www.oreilly.com/library/view/functional-programming-in/9781492048633/ – elliotwesoff Jun 15 '20 at 22:48
10

Before Python 3, map() returned a list, not an iterator. So your example would work in Python 2.7.

list() creates a new list by iterating over its argument. ( list() is NOT JUST a type conversion from say tuple to list. So list(list((1,2))) returns [1,2]. ) So list(map(...)) is backwards compatible with Python 2.7.

bootchk
  • 1,926
  • 17
  • 14
2

I just want to add the following:

With multiple iterables, the iterator stops when the shortest iterable is exhausted [ https://docs.python.org/3.4/library/functions.html#map ]

Python 2.7.6 (default, Mar 22 2014, 22:59:56)

>>> list(map(lambda a, b: [a, b], [1, 2, 3], ['a', 'b']))
[[1, 'a'], [2, 'b'], [3, None]]

Python 3.4.0 (default, Apr 11 2014, 13:05:11)

>>> list(map(lambda a, b: [a, b], [1, 2, 3], ['a', 'b']))
[[1, 'a'], [2, 'b']]

That difference makes the answer about simple wrapping with list(...) not completely correct

The same could be achieved with:

>>> import itertools
>>> [[a, b] for a, b in itertools.zip_longest([1, 2, 3], ['a', 'b'])]
[[1, 'a'], [2, 'b'], [3, None]]
Grief
  • 1,839
  • 1
  • 21
  • 40