156 lines
5.0 KiB
Plaintext
156 lines
5.0 KiB
Plaintext
PEP: 274
|
||
Title: Dict Comprehensions
|
||
Version: $Revision$
|
||
Last-Modified: $Date$
|
||
Author: barry@python.org (Barry Warsaw)
|
||
Status: Withdrawn
|
||
Type: Standards Track
|
||
Created: 25-Oct-2001
|
||
Python-Version: 2.3
|
||
Post-History: 29-Oct-2001
|
||
|
||
|
||
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.
|
||
|
||
Resolution
|
||
|
||
This PEP is withdrawn. Substantially all of its benefits were
|
||
subsumed by generator expressions coupled with the dict() constructor.
|
||
|
||
However, Python 3.0 introduces this exact feature, as well as the
|
||
closely related set comprehensions.
|
||
|
||
|
||
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 dict() constructor accepts an argument that is
|
||
a sequence of length-2 sequences, used as (key, value) pairs to
|
||
initialize a new dictionary object.
|
||
|
||
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.
|
||
|
||
|
||
Semantics
|
||
|
||
The semantics of dict comprehensions can actually be demonstrated
|
||
in stock Python 2.2, by passing a list comprehension to the
|
||
builtin dictionary constructor:
|
||
|
||
>>> dict([(i, chr(65+i)) for i in range(4)])
|
||
|
||
is semantically equivalent to
|
||
|
||
>>> {i : chr(65+i) for i in range(4)}
|
||
|
||
The dictionary constructor approach has two dictinct disadvantages
|
||
from the proposed syntax though. First, it 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.
|
||
|
||
|
||
Examples
|
||
|
||
>>> print {i : chr(65+i) for i in range(4)}
|
||
{0 : 'A', 1 : 'B', 2 : 'C', 3 : 'D'}
|
||
|
||
>>> print {k : v for k, v in someDict.iteritems()} == someDict.copy()
|
||
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):
|
||
... return {v : k for k, v in d.iteritems()}
|
||
...
|
||
>>> d = {0 : 'A', 1 : 'B', 2 : 'C', 3 : 'D'}
|
||
>>> print invert(d)
|
||
{'A' : 0, 'B' : 1, 'C' : 2, 'D' : 3}
|
||
|
||
>>> {(k, v): k+v for k in range(4) for v in range(4)}
|
||
... {(3, 3): 6, (3, 2): 5, (3, 1): 4, (0, 1): 1, (2, 1): 3,
|
||
(0, 2): 2, (3, 0): 3, (0, 3): 3, (1, 1): 2, (1, 0): 1,
|
||
(0, 0): 0, (1, 2): 3, (2, 0): 2, (1, 3): 4, (2, 2): 4, (
|
||
2, 3): 5}
|
||
|
||
|
||
Open Issues
|
||
|
||
- 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:
|
||
|
||
>>> print {1 for x in list_of_email_addrs}
|
||
{'barry@zope.com' : 1, 'barry@python.org' : 1, 'guido@python.org' : 1}
|
||
|
||
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.
|
||
|
||
|
||
Implementation
|
||
|
||
TBD
|
||
|
||
|
||
References
|
||
|
||
[1] PEP 202, List Comprehensions
|
||
http://www.python.org/dev/peps/pep-0202/
|
||
|
||
|
||
Copyright
|
||
|
||
This document has been placed in the public domain.
|
||
|
||
|
||
|
||
Local Variables:
|
||
mode: indented-text
|
||
indent-tabs-mode: nil
|
||
fill-column: 70
|
||
End:
|