It would be nice if there were only one “obvious way to do it”, in general, but this is almost always a pipe dream. Different people will find different things obvious. This rule is meant more for the language designers than it is for programmers: when there is a common task that needs a few lines of code, and people write the code in different ways, and every way takes a little bit of thought… then this is a suggestion to make the language give some more explicit support. Even if everyone does it the same way, it shouldn’t seem too abstract. Following this principle is how we get nice conveniences such as random.choice
.
As for map
vs. list comprehensions, this is my personal guidance:
List comprehensions are usually preferred.
Consider map
when:
-
the function you want to apply already exists (especially if it is a builtin):
>>> # Not bad
>>> [str(x) for x in range(10)]
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
>>> # the map way is eta-reduced, which can be considered an advantage
>>> list(map(str, range(10)))
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
See also about eta-reduction (also called eta-conversion), in a language where people usually care a lot more about this kind of thing 
Edit: I forgot to mention - when the function is a built-in, the map
approach is typically more performant. Or at least, it used to be, the last time I tested it.
-
you can write the transformation easily as a function and that function needs to take multiple arguments from parallel input lists:
>>> [x*y for x, y in zip(range(10), range(10, 20))]
[0, 11, 24, 39, 56, 75, 96, 119, 144, 171]
>>> # the map way has the "zipping" built in already:
>>> list(map(lambda x, y: x*y, range(10), range(10, 20)))
[0, 11, 24, 39, 56, 75, 96, 119, 144, 171]
Especially prefer a list comprehension when you also need a filter
:
>>> # ew
>>> list(map(lambda x: x + 1, filter(lambda x: x % 3, range(10))))
[2, 3, 5, 6, 8, 9]
>>> # much easier
>>> [x + 1 for x in range(10) if x % 3]
[2, 3, 5, 6, 8, 9]
In Python 3.x, map
is lazy. If you need or want that lazy result but want to use the list comprehension syntax, write a generator expression instead:
>>> [x for x in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> (x for x in range(10)) # This does not make a tuple.
<generator object <genexpr> at 0x7f1ddd439120>
The resulting “generator object” can be used in all the same basic ways as the map
result. (There are technical differences, but they aren’t important here.)
Please don’t write an explicit loop for ordinary cases. Figuring out how to build a list from the results should be Python’s job, not yours. The .append
method is not interesting, and the imperative logic to build the list is a distraction from the core idea: i.e., the rule that tells you how the output list elements relate to the input list elements.