There is a withdrawn PEP about a new syntax for dict comprehension:
http://www.python.org/dev/peps/pep-0274/ which says:
"Substantially all of its benefits were subsumed by generator
expressions coupled with the dict() constructor."
What does the author mean here? What's the Preferably One Way (TM) to
do something analogous to a dict comprehension?
I imagine something like this:
>>> keys = "a b c".split()
>>> values = [1, 2, 3]
>>> D = dict([(a, b) for a, b in zip(keys, values)])
>>> D
{'a': 1, 'c': 3, 'b': 2}
Regards,
Ryan Ginstrom
from itertools import izip
d = dict((k,v) for k,v in izip(keys, values))
The dict builtin can build a dictionary from a list (or iterator or
generator creating a list) of tuples. Put them together and get what
you might be tempted to call a dictionary comprehension. For instance:
>>> dict((i,i*i) for i in range(10))
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
Gary Herron
Hi Ryan, that uses a list comprehension.
The generator comprehension is:
D = dict((a, b) for a, b in zip(keys, values))
(No square brackets)
- Paddy.
>>> keys = "a b c".split()
>>> values = [1, 2, 3]
>>> D = dict((a, b) for a, b in zip(keys, values))
Neat!
I believe both set and dict comprehensions will be in 3.0.
Python 3.0a1+ (py3k:59330, Dec 4 2007, 18:44:39)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> {x*x for x in range(10)}
{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}
>>>
That's nice.
--
Arnaud
Why not just
D = dict(zip(keys,values))
??
-- Paul
Because this may require less memory:
from itertools import izip
D = dict(izip(keys, values))
:-)
Bear hugs,
bearophile
Also, what is that first thing? A valueless dict (and thus a set)?
/W
It's a literal syntax, just like you would do with a list, i.e. a list
comprehension. Why should you have list comps and no dict comps?
> Also, what is that first thing? A valueless dict (and thus a set)?
It's the literal set syntax added in 3.0. You can write
{1,2,3}
to get a set() or
{1:1,2:2}
to get a dict().
Stefan
It's more than twice as fast:
>>> setup = "items = range(10)"
>>> timeit.Timer("dict((x, x * x) for x in items)", setup).timeit()
6.0559464959932114
>>> timeit.Timer("{x:x * x for x in items}", setup).timeit()
2.8347301821879682
It also doesn't build the unnecessary intermediate tuples:
>>> def dict_genexp(items):
... return dict((x, x * x) for x in items)
...
>>> def dict_comp(items):
... return {x:x * x for x in items}
...
>>> dis.dis(dict_genexp.__code__.co_consts[1])
2 0 LOAD_FAST 0 (.0)
>> 3 FOR_ITER 21 (to 27)
6 STORE_FAST 1 (x)
9 LOAD_FAST 1 (x)
12 LOAD_FAST 1 (x)
15 LOAD_FAST 1 (x)
18 BINARY_MULTIPLY
19 BUILD_TUPLE 2
22 YIELD_VALUE
23 POP_TOP
24 JUMP_ABSOLUTE 3
>> 27 LOAD_CONST 0 (None)
30 RETURN_VALUE
>>> dis.dis(dict_comp.__code__.co_consts[1])
2 0 BUILD_MAP 0
3 DUP_TOP
4 STORE_FAST 1 (_[1])
7 LOAD_FAST 0 (.0)
>> 10 FOR_ITER 21 (to 34)
13 STORE_FAST 2 (x)
16 LOAD_FAST 1 (_[1])
19 LOAD_FAST 2 (x)
22 LOAD_FAST 2 (x)
25 BINARY_MULTIPLY
26 ROT_TWO
27 LOAD_FAST 2 (x)
30 STORE_SUBSCR
31 JUMP_ABSOLUTE 10
>> 34 RETURN_VALUE
STeVe
I see, but can't the interpreter improved to remove similar
intermediate tuples anyway? Is this a difficult thing to do?
Bye,
bearophile
Do you mean the compiler?
> Is this a difficult thing to do?
Yes, due to the HDNP (Highly Dynamic Nature of Python).
--
Arnaud