Dictionary from list?

Tim Peters tim.one at home.com
Mon Oct 22 09:49:53 CEST 2001

[Andrew Dalke]
> Not a core function, but
> args, files = getopt.getopt(...)
> args = dictionary(args)
> would be handy.

And Marcin Kowalczyk had some good abstract arguments -- but a concrete
example somebody would actually use does more for me <wink>.

So what should dictionary(x) do?

If x is of a mapping type, it currently (2.2b1) returns a dict with the same
(key, value) pairs as x.  "Is a mapping type" == is an instance of
dictionary (including subclasses of dictionary), or, failing that, responds
to x.keys() without raising AttributeError.

If we try x.keys() and do see AttributeError, then what?  It's not 2.2-ish
to insist on a list -- any iterable object should work.  So we try to
iterate over x.  Now it gets harder:  what kinds of objects are we prepared
to see when iterating x?  Insisting on a 2-tuple (or subclass of tuple) is
most efficient.  More general is to treat these as iterable objects in their
own right, and either take the first two objects iteration produces, or
insist that an attempt to generate a third object raise StopIteration.  The
latter is more Pythonic, because it matches what "the obvious" loop does:

d = {}
for k, v in x:
    d[k] = v

In 2.2, x can be any iterable object there, and so can the objects produced
by iterating *over* x.  Extreme example of the latter:

>>> f = file('f1', 'w')
>>> f.write('a\nb\n')
>>> f.close()
>>> g = file('f2', 'w')
>>> g.write('c\nd\n')
>>> g.close()
>>> h = file('f3', 'w')
>>> h.write('1\n2\n3\n')
>>> h.close()
>>> for k, v in map(file, ('f1', 'f2', 'f3')):
...     print k, v


Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ValueError: too many values to unpack

That is, we can't unpack a file with 3 lines into a two-vrbl assignment
target.  Is 2.2 great or what <0.9 wink>?!

OK, I convinced myself that's the only explainable thing to be done,
although I grate at the gross inefficiences; but I can special-case 2-tuples
and 2-lists for speed, so that's OK.

Next question:  Should this really work by provoking the argument with
various protocols and letting exceptions steer it?  Or should you be
explicit about that you're passing an iterable object producing iterable
objects producing 2 objects each?

dictionary() currently takes a single optional argument, named 'mapping':

>>> dictionary(mapping={1: 2})
{1: 2}
>>> dictionary({1: 2}) # same thing
{1: 2}

Should the new behavior require use of a differently-named keyword argument?
My guess is yes.  What will prevent this from getting implemented is a
3-year rancorous debate about the name of the new argument <0.7 wink>.

Note that the obvious workalike loop:

d = {}
for k, v in x:
    d[k] = v

deals with duplicate k values by silently overwriting all but the last
association seen.

"tough-luck"-comes-to-mind-ly y'rs  - tim

More information about the Python-list mailing list