Learning Python - Mark Lutz [281]
3.0 Comprehension Syntax Summary
We’ve been focusing on list comprehensions and generators in this chapter, but keep in mind that there are two other comprehension expression forms: set and dictionary comprehensions are also available as of Python 3.0. We met these briefly in Chapters 5 and 8, but with our new knowledge of comprehensions and generators, you should now be able to grasp these 3.0 extensions in full:
For sets, the new literal form {1, 3, 2} is equivalent to set([1, 3, 2]), and the new set comprehension syntax {f(x) for x in S if P(x)} is like the generator expression set(f(x) for x in S if P(x)), where f(x) is an arbitrary expression.
For dictionaries, the new dictionary comprehension syntax {key: val for (key, val) in zip(keys, vals)} works like the form dict(zip(keys, vals)), and {x: f(x) for x in items} is like the generator expression dict((x, f(x)) for x in items).
Here’s a summary of all the comprehension alternatives in 3.0. The last two are new and are not available in 2.6:
>>> [x * x for x in range(10)] # List comprehension: builds list
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # like list(generator expr)
>>> (x * x for x in range(10)) # Generator expression: produces items
>>> {x * x for x in range(10)} # Set comprehension, new in 3.0 {0, 1, 4, 81, 64, 9, 16, 49, 25, 36} # {x, y} is a set in 3.0 too >>> {x: x * x for x in range(10)} # Dictionary comprehension, new in 3.0 {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81} Comprehending Set and Dictionary Comprehensions In a sense, set and dictionary comprehensions are just syntactic sugar for passing generator expressions to the type names. Because both accept any iterable, a generator works well here: >>> {x * x for x in range(10)} # Comprehension {0, 1, 4, 81, 64, 9, 16, 49, 25, 36} >>> set(x * x for x in range(10)) # Generator and type name {0, 1, 4, 81, 64, 9, 16, 49, 25, 36} >>> {x: x * x for x in range(10)} {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81} >>> dict((x, x * x) for x in range(10)) {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81} As for list comprehensions, though, we can always build the result objects with manual code, too. Here are statement-based equivalents of the last two comprehensions: >>> res = set() >>> for x in range(10): # Set comprehension equivalent ... res.add(x * x) ... >>> res {0, 1, 4, 81, 64, 9, 16, 49, 25, 36} >>> res = {} >>> for x in range(10): # Dict comprehension equivalent ... res[x] = x * x ... >>> res {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81} Notice that although both forms accept iterators, they have no notion of generating results on demand—both forms build objects all at once. If you mean to produce keys and values upon request, a generator expression is more appropriate: >>> G = ((x, x * x) for x in range(10)) >>> next(G) (0, 0) >>> next(G) (1, 1) Extended Comprehension Syntax for Sets and Dictionaries Like list comprehensions and generator expressions, both set and dictionary comprehensions support nested associated if clauses to filter items out of the result—the following collect squares of even items (i.e., items having no remainder for division by 2) in a range: >>> [x * x for x in range(10) if x % 2 == 0] # Lists are