16 comments

[ 2.9 ms ] story [ 43.1 ms ] thread
map() isn't all that useful in Python.

If you want a list it's more straightforward to write:

    [f(x) for x in my_iterable]
If you don't want a list it's more straightforward to write:

    for x in my_iterable:
        y = f(x)
I guess it's all about your definition of 'straightforward' ;)
I tend to use map if my mapping function is already available to me as a callable. If I would use a lambda, I tend to use a list or generator expression instead.

Probably my single most common usage of map is:

    s = sep.join(map(str, parts))
because join() refuses to join anything that isn't a str, and map is a nice way to stringify all elements of a list.
The alternative would be:

    s = sep.join([str(part) for part in parts])
I agree this is one of the cases where map looks nicer than list comprehensions or generator expressions.
You can also use a generator expression so you don't have to create a list:

    s = sep.join(str(part) for part in parts)
Python 101: str() is dangerous for unicode objects without a specified encoding. Please don't call str() unless you know exactly what encoding you are dealing with.

Try it:

    $ LC_ALL=en_US.UTF-8 python -c "print str(u'é')"
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
    UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
To perhaps shed a little light on the None thing and why it would be useful, consider the following:

    def munge(data, convert=None):
        data = map(convert, data)
        ...
ie. treating None as identity gives you sane default behaviour in the case that you want to optionally provide a mapping functionality. Granted, you can easily do an "if convert is not None" but I think this is slightly nicer.

Welp, add it to the list of things I think are better in py2 than py3.

Or you could do

   def munge(data, convert=lambda x: x)
This is C++ style thinking, but that way it has to copy the array and run that function on every element. If it supports none it can just return the original data.
> but I hope none of pythonistas will use it and one day it will be removed from the language.

This behaviour for map with None is no longer present in python3 and raises a TypeError.

No comments yet about why in Python 3 the map behavior changed when the iterables are of different lengths? That seems like a gratuitous change. How is that better (not just different) than what Python 2 did?

Also, there was one other change in Python 3 that should have been left alone. I'm stealing the meme from a previous poster on HN:

   Python 3 broke "Hello, World!"
Why? Why couldn't that "wart" have been left the way it was? Sometimes it's smarter to not change something, especially if that change breaks nearly 100% of existing programs.
IIRC the change is related to the change in `iter` which in python2 returns `None` after exhausting a list but in python3 will raise `StopIteration`.

Very annoying TBH. I had some really nice list chunking functions using `map` on python2 that no longer work on python3.

    map(lambda x: x, ['a', 'b', 'c'], [1, 2])
This should be

     map(lambda x, y: (x, y), ['a', 'b', 'c'], [1, 2])
If you want the same behavior as passing None as the first argument.
I am surprised nobody mentioned this yet.

     filter(None, [0 1, 2, 3, False, None, 5, 6, 7])
Here None is the same as bool()