2001-10-25 16:28:05 -04:00
|
|
|
|
PEP: 274
|
|
|
|
|
Title: Dict Comprehensions
|
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
|
|
|
|
Author: barry@zope.com (Barry A. Warsaw)
|
|
|
|
|
Status: Draft
|
|
|
|
|
Type: Standards Track
|
|
|
|
|
Created: 25-Oct-2001
|
|
|
|
|
Python-Version: 2.3
|
2001-10-29 13:46:59 -05:00
|
|
|
|
Post-History: 29-Oct-2001
|
2001-10-25 16:28:05 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
|
|
|
|
|
PEP 202 introduces a syntactical extension to Python called the
|
|
|
|
|
"list comprehension"[1]. This PEP proposes a similar syntactical
|
|
|
|
|
extension called the "dictionary comprehension" or "dict
|
|
|
|
|
comprehension" for short. You can use dict comprehensions in ways
|
|
|
|
|
very similar to list comprehensions, except that they produce
|
|
|
|
|
Python dictionary objects instead of list objects.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Proposed Solution
|
|
|
|
|
|
|
|
|
|
Dict comprehensions are just like list comprehensions, except that
|
|
|
|
|
you group the expression using curly braces instead of square
|
|
|
|
|
braces. Also, the left part before the `for' keyword expresses
|
|
|
|
|
both a key and a value, separated by a colon. (There is an
|
|
|
|
|
optional part of this PEP that allows you to use a shortcut to
|
|
|
|
|
express just the value.) The notation is specifically designed to
|
|
|
|
|
remind you of list comprehensions as applied to dictionaries.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Rationale
|
|
|
|
|
|
|
|
|
|
There are times when you have some data arranged as a sequences of
|
|
|
|
|
length-2 sequences, and you want to turn that into a dictionary.
|
|
|
|
|
In Python 2.2, the dictionary() constructor will take an optional
|
|
|
|
|
keyword argument that indicates specifically to interpret a
|
|
|
|
|
sequences of length-2 sequences as key/value pairs, and turn them
|
|
|
|
|
into a dictionary.
|
|
|
|
|
|
|
|
|
|
However, the act of turning some data into a sequence of length-2
|
|
|
|
|
sequences can be inconvenient or inefficient from a memory or
|
|
|
|
|
performance standpoint. Also, for some common operations, such as
|
|
|
|
|
turning a list of things into a set of things for quick duplicate
|
|
|
|
|
removal or set inclusion tests, a better syntax can help code
|
|
|
|
|
clarity.
|
|
|
|
|
|
|
|
|
|
As with list comprehensions, an explicit for loop can always be
|
|
|
|
|
used (and in fact was the only way to do it in earlier versions of
|
|
|
|
|
Python). But as with list comprehensions, dict comprehensions can
|
|
|
|
|
provide a more syntactically succinct idiom that the traditional
|
|
|
|
|
for loop.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Examples
|
|
|
|
|
|
|
|
|
|
>>> print {i : chr(65+i) for i in range(4)}
|
|
|
|
|
{0 : 'A', 1 : 'B', 2 : 'C', 3 : 'D'}
|
|
|
|
|
|
2001-10-29 13:46:59 -05:00
|
|
|
|
>>> print {k : v for k, v in someDict.iteritems()} == someDict.copy()
|
2001-10-25 16:28:05 -04:00
|
|
|
|
1
|
|
|
|
|
|
|
|
|
|
>>> print {x.lower() : 1 for x in list_of_email_addrs}
|
|
|
|
|
{'barry@zope.com' : 1, 'barry@python.org' : 1, 'guido@python.org' : 1}
|
|
|
|
|
|
|
|
|
|
>>> def invert(d):
|
2001-10-29 13:46:59 -05:00
|
|
|
|
... return {v : k for k, v in d.iteritems()}
|
2001-10-25 16:28:05 -04:00
|
|
|
|
...
|
|
|
|
|
>>> d = {0 : 'A', 1 : 'B', 2 : 'C', 3 : 'D'}
|
|
|
|
|
>>> print invert(d)
|
2001-10-29 13:46:59 -05:00
|
|
|
|
{'A' : 0, 'B' : 1, 'C' : 2, 'D' : 3}
|
2001-10-25 16:28:05 -04:00
|
|
|
|
|
|
|
|
|
|
2001-10-29 13:46:59 -05:00
|
|
|
|
Open Issues
|
2001-10-25 16:28:05 -04:00
|
|
|
|
|
2001-10-29 13:46:59 -05:00
|
|
|
|
- There is one further shortcut we could adopt. Suppose we wanted
|
|
|
|
|
to create a set of items, such as in the "list_of_email_addrs"
|
|
|
|
|
example above. Here, we're simply taking the target of the for
|
|
|
|
|
loop and turning that into the key for the dict comprehension.
|
|
|
|
|
The assertion is that this would be a common idiom, so the
|
|
|
|
|
shortcut below allows for an easy spelling of it, by allow us to
|
|
|
|
|
omit the "key :" part of the left hand clause:
|
2001-10-25 16:28:05 -04:00
|
|
|
|
|
2001-10-29 13:46:59 -05:00
|
|
|
|
>>> print {1 for x in list_of_email_addrs}
|
|
|
|
|
{'barry@zope.com' : 1, 'barry@python.org' : 1, 'guido@python.org' : 1}
|
2001-10-25 16:28:05 -04:00
|
|
|
|
|
2001-10-29 13:46:59 -05:00
|
|
|
|
Or say we wanted to map email addresses to the MX record handling
|
|
|
|
|
their mail:
|
|
|
|
|
|
|
|
|
|
>>> print {mx_for_addr(x) for x in list_of_email_addrs}
|
|
|
|
|
{'barry@zope.com' : 'mail.zope.com',
|
|
|
|
|
'barry@python.org' : 'mail.python.org,
|
|
|
|
|
'guido@python.org' : 'mail.python.org,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Questions: what about nested loops? Where does the key come
|
|
|
|
|
from? The shortcut probably doesn't save much typing, and comes
|
|
|
|
|
at the expense of legibility, so it's of dubious value.
|
|
|
|
|
|
|
|
|
|
- Should nested for loops be allowed? The following example,
|
|
|
|
|
taken from an earlier revision of this PEP illustrates the
|
|
|
|
|
problem:
|
|
|
|
|
|
|
|
|
|
>>> print {k, v for k in range(4) for v in range(-4, 0, 1)}
|
|
|
|
|
|
|
|
|
|
The intent of this example was to produce a mapping from a
|
|
|
|
|
number to its negative, but this code doesn't work because -- as
|
|
|
|
|
in list comprehensions -- the for loops are nested, not in
|
|
|
|
|
parallel! So the value of this expression is actually
|
|
|
|
|
|
|
|
|
|
{0: -1, 1: -1, 2: -1, 3: -1}
|
|
|
|
|
|
|
|
|
|
which seems of dubious value. For symmetry with list
|
|
|
|
|
comprehensions, perhaps this should be allowed, but it might be
|
|
|
|
|
better to disallow this syntax.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Implementation
|
|
|
|
|
|
|
|
|
|
The semantics of dictionary comprehensions can actually be modeled
|
|
|
|
|
in stock Python 2.2, by passing a list comprehension to the
|
|
|
|
|
builtin dictionary constructor:
|
2001-10-25 16:28:05 -04:00
|
|
|
|
|
2001-10-29 13:46:59 -05:00
|
|
|
|
>>> dictionary([(i, chr(65+i)) for i in range(4)])
|
2001-10-25 16:28:05 -04:00
|
|
|
|
|
2001-10-29 13:46:59 -05:00
|
|
|
|
This has two dictinct disadvantages from the proposed syntax
|
|
|
|
|
though. First, it's isn't as legible as a dict comprehension.
|
|
|
|
|
Second, it forces the programmer to create an in-core list object
|
|
|
|
|
first, which could be expensive.
|
2001-10-25 16:28:05 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
References
|
|
|
|
|
|
|
|
|
|
[1] PEP 202, List Comprehensions
|
|
|
|
|
http://www.python.org/peps/pep-0202.html
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Copyright
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
fill-column: 70
|
|
|
|
|
End:
|