Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

dict comprehension

6 views
Skip to first unread message

Daniel Fetchinson

unread,
Feb 1, 2008, 12:51:12 AM2/1/08
to pytho...@python.org
Hi folks,

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?

Ryan Ginstrom

unread,
Feb 1, 2008, 1:06:16 AM2/1/08
to pytho...@python.org
> On Behalf Of Daniel Fetchinson

> 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

Paul Rubin

unread,
Feb 1, 2008, 1:10:14 AM2/1/08
to
"Daniel Fetchinson" <fetch...@googlemail.com> writes:
> What does the author mean here? What's the Preferably One Way (TM) to
> do something analogous to a dict comprehension?

from itertools import izip
d = dict((k,v) for k,v in izip(keys, values))

Gary Herron

unread,
Feb 1, 2008, 1:10:04 AM2/1/08
to Daniel Fetchinson, pytho...@python.org
Daniel Fetchinson wrote:
> Hi folks,
>
> 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?
>
See about generator expressions in
http://www.python.org/doc/2.4/whatsnew/node4.html.

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


Paddy

unread,
Feb 1, 2008, 1:13:58 AM2/1/08
to

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.

Gary Herron

unread,
Feb 1, 2008, 1:14:49 AM2/1/08
to Ryan Ginstrom, pytho...@python.org
Ryan Ginstrom wrote:
>> On Behalf Of Daniel Fetchinson
>> 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
>
>
This fine example uses list comprehension to build a list of tuples
which is than read by the dict builtin to create a dictionary. You can
dispense with the intermediate list if you use a generator expression
directly as input to the dict builtin. (Requires Python 2.4 or later.)
Like this:

>>> keys = "a b c".split()
>>> values = [1, 2, 3]

>>> D = dict((a, b) for a, b in zip(keys, values))

Daniel Fetchinson

unread,
Feb 1, 2008, 1:18:35 AM2/1/08
to pytho...@python.org
> > Hi folks,
> >
> > 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?
> >
> See about generator expressions in
> http://www.python.org/doc/2.4/whatsnew/node4.html.
>
> 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}

Neat!

Terry Reedy

unread,
Feb 1, 2008, 1:21:01 AM2/1/08
to pytho...@python.org

"Daniel Fetchinson" <fetch...@googlemail.com> wrote in message
news:fbe2e2100801312151x713...@mail.gmail.com...

| Hi folks,
|
| There is a withdrawn PEP about a new syntax for dict comprehension:
| http://www.python.org/dev/peps/pep-0274/ which says:

I believe both set and dict comprehensions will be in 3.0.

Arnaud Delobelle

unread,
Feb 1, 2008, 2:13:37 AM2/1/08
to
On Feb 1, 6:21 am, "Terry Reedy" <tjre...@udel.edu> wrote:
> "Daniel Fetchinson" <fetchin...@googlemail.com> wrote in message

>
> news:fbe2e2100801312151x713...@mail.gmail.com...
> | Hi folks,
> |
> | There is a withdrawn PEP about a new syntax for dict comprehension:
> |http://www.python.org/dev/peps/pep-0274/which says:
>
> 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

Paul McGuire

unread,
Feb 1, 2008, 3:19:16 AM2/1/08
to

Why not just

D = dict(zip(keys,values))

??

-- Paul

bearoph...@lycos.com

unread,
Feb 1, 2008, 5:09:55 AM2/1/08
to
Paul McGuire:

> Why not just
> D = dict(zip(keys,values))
> ??

Because this may require less memory:

from itertools import izip
D = dict(izip(keys, values))

:-)

Bear hugs,
bearophile

Wildemar Wildenburger

unread,
Feb 1, 2008, 8:38:59 AM2/1/08
to
Arnaud Delobelle wrote:
>> 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}
>
OK, not bad. But I don't really see how this is better than the
generator approach.

Also, what is that first thing? A valueless dict (and thus a set)?

/W

Stefan Behnel

unread,
Feb 1, 2008, 12:29:54 PM2/1/08
to Wildemar Wildenburger
Wildemar Wildenburger wrote:
> Arnaud Delobelle wrote:
>>> 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}
>>
> OK, not bad. But I don't really see how this is better than the
> generator approach.

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

Steven Bethard

unread,
Feb 2, 2008, 1:06:54 PM2/2/08
to
Wildemar Wildenburger wrote:
> Arnaud Delobelle wrote:
>>> 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}
>>
> OK, not bad. But I don't really see how this is better than the
> generator approach.

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

bearoph...@lycos.com

unread,
Feb 2, 2008, 4:10:46 PM2/2/08
to
Steven Bethard:

> It also doesn't build the unnecessary intermediate tuples:

I see, but can't the interpreter improved to remove similar
intermediate tuples anyway? Is this a difficult thing to do?

Bye,
bearophile

Arnaud Delobelle

unread,
Feb 3, 2008, 4:02:47 AM2/3/08
to
On Feb 2, 9:10 pm, bearophileH...@lycos.com wrote:
> Steven Bethard:
>
> > It also doesn't build the unnecessary intermediate tuples:
>
> I see, but can't the interpreter improved to remove similar
> intermediate tuples anyway?

Do you mean the compiler?

> Is this a difficult thing to do?

Yes, due to the HDNP (Highly Dynamic Nature of Python).

--
Arnaud

0 new messages