Mapping Functions over Sequences: map

One of the more common things programs do with lists and other sequences is apply an operation to each item and collect the results. For instance, updating all the counters in a list can be done easily with a for loop:

>>> counters = [1, 2, 3, 4]
>>>
>>> updated = []
>>> for x in counters:
...     updated.append(x + 10)                 # Add 10 to each item
...
>>> updated
[11, 12, 13, 14]

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

But because this is such a common operation, Python actually provides a built-in that does most of the work for you. The map function applies a passed-in function to each item in an iterable object and returns a list containing all the function call results. For example:

>>> def inc(x): return x + 10                  # Function to be run
...
>>> list(map(inc, counters))                   # Collect results
[11, 12, 13, 14]

We met map briefly in Chapters 13 and 14, as a way to apply a built-in function to items in an iterable. Here, we make better use of it by passing in a user-defined function to be applied to each item in the list—map calls inc on each list item and collects all the return values into a new list. Remember that map is an iterable in Python 3.0, so a list call is used to force it to produce all its results for display here; this isn’t necessary in 2.6.

Because map expects a function to be passed in, it also happens to be one of the places where lambda commonly appears:

>>> list(map((lambda x: x + 3), counters))     # Function expression
[4, 5, 6, 7]

Here, the function adds 3 to each item in the counters list; as this little function isn’t needed elsewhere, it was written inline as a lambda. Because such uses of map are equivalent to for loops, with a little extra code you can always code a general mapping utility yourself:

>>> def mymap(func, seq):
...     res = []
...     for x in seq: res.append(func(x))
...     return res

Assuming the function inc is still as it was when it was shown previously, we can map it across a sequence with the built-in or our equivalent:

>>> list(map(inc, [1, 2, 3]))             # Built-in is an iterator
[11, 12, 13]
>>> mymap(inc, [1, 2, 3])                 # Ours builds a list (see generators)
[11, 12, 13]

However, as map is a built-in, it’s always available, always works the same way, and has some performance benefits (as we’ll prove in the next chapter, it’s usually faster than a manually coded for loop). Moreover, map can be used in more advanced ways than shown here. For instance, given multiple sequence arguments, it sends items taken from sequences in parallel as distinct arguments to the function:

>>> pow(3, 4)                             # 3**4
81
>>> list(map(pow, [1, 2, 3], [2, 3, 4]))  # 1**2, 2**3, 3**4
[1, 8, 81]

With multiple sequences, map expects an N-argument function for N sequences. Here, the pow function takes two arguments on each call—one from each sequence passed to map. It’s not much extra work to simulate this multiple-sequence generality in code, too, but we’ll postpone doing so until later in the next chapter, after we’ve met some additional iteration tools.

The map call is similar to the list comprehension expressions we studied in Chapter 14 and will meet again in the next chapter, but map applies a function call to each item instead of an arbitrary expression. Because of this limitation, it is a somewhat less general tool. However, in some cases map may be faster to run than a list comprehension (e.g., when mapping a built-in function), and it may also require less coding.