预计阅读本页时间:-
Comprehending List Comprehensions
With such generality, list comprehensions can quickly become, well, incomprehensible, especially when nested. Consequently, my advice is typically to use simple for loops when getting started with Python, and map or comprehensions in isolated cases where they are easy to apply. The “keep it simple” rule applies here, as always: code conciseness is a much less important goal than code readability.
However, in this case, there is currently a substantial performance advantage to the extra complexity: based on tests run under Python today, map calls are roughly twice as fast as equivalent for loops, and list comprehensions are usually slightly faster than map calls.[43] This speed difference is generally due to the fact that map and list comprehensions run at C language speed inside the interpreter, which is much faster than stepping through Python for loop code within the PVM.
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
Because for loops make logic more explicit, I recommend them in general on the grounds of simplicity. However, map and list comprehensions are worth knowing and using for simpler kinds of iterations, and if your application’s speed is an important consideration. In addition, because map and list comprehensions are both expressions, they can show up syntactically in places that for loop statements cannot, such as in the bodies of lambda functions, within list and dictionary literals, and more. Still, you should try to keep your map calls and list comprehensions simple; for more complex tasks, use full statements instead.
Why You Will Care: List Comprehensions and map
Here’s a more realistic example of list comprehensions and map in action (we solved this problem with list comprehensions in Chapter 14, but we’ll revive it here to add map-based alternatives). Recall that the file readlines method returns lines with \n end-of-line characters at the ends:
>>> open('myfile').readlines()
['aaa\n', 'bbb\n', 'ccc\n']
If you don’t want the end-of-line characters, you can slice them off all the lines in a single step with a list comprehension or a map call (map results are iterables in Python 3.0, so we must run them through list to see all their results at once):
>>> [line.rstrip() for line in open('myfile').readlines()]
['aaa', 'bbb', 'ccc']
>>> [line.rstrip() for line in open('myfile')]
['aaa', 'bbb', 'ccc']
>>> list(map((lambda line: line.rstrip()), open('myfile')))
['aaa', 'bbb', 'ccc']
The last two of these make use of file iterators (which essentially means that you don’t need a method call to grab all the lines in iteration contexts such as these). The map call is slightly longer than the list comprehension, but neither has to manage result list construction explicitly.
A list comprehension can also be used as a sort of column projection operation. Python’s standard SQL database API returns query results as a list of tuples much like the following—the list is the table, tuples are rows, and items in tuples are column values:
listoftuple = [('bob', 35, 'mgr'), ('mel', 40, 'dev')]
A for loop could pick up all the values from a selected column manually, but map and list comprehensions can do it in a single step, and faster:
>>> [age for (name, age, job) in listoftuple]
[35, 40]
>>> list(map((lambda row: row[1]), listoftuple))
[35, 40]
The first of these makes use of tuple assignment to unpack row tuples in the list, and the second uses indexing. In Python 2.6 (but not in 3.0—see the note on 2.6 argument unpacking in Chapter 18), map can use tuple unpacking on its argument, too:
# 2.6 only
>>> list(map((lambda (name, age, job): age), listoftuple))
[35, 40]
See other books and resources for more on Python’s database API.
Beside the distinction between running functions versus expressions, the biggest difference between map and list comprehensions in Python 3.0 is that map is an iterator, generating results on demand; to achieve the same memory economy, list comprehensions must be coded as generator expressions (one of the topics of this chapter).
[43] These performance generalizations can depend on call patterns, as well as changes and optimizations in Python itself. Recent Python releases have sped up the simple for loop statement, for example. Usually, though, list comprehensions are still substantially faster than for loops and even faster than map (though map can still win for built-in functions). To time these alternatives yourself, see the standard library’s time module’s time.clock and time.time calls, the newer timeit module added in Release 2.4, or this chapter’s upcoming section Timing Iteration Alternatives.