[Python-Dev] dict.addlist()

Guido van Rossum guido at python.org
Tue Jan 20 10:34:53 EST 2004


> Here is anidea to kick around:
> 
> Evolve and eventually replace dict.setdefault with a more specialized 
> method that is clearer, cleaner, easier to use, and faster.
> 
>        d.addlist(k, v)   would work like   d.setdefault(k, []).append(v)
>        
> 
> Raymond Hettinger
> 
> 
> >>> d = dict()
> >>> for elem in 'apple orange ant otter banana asp onyx boa'.split():
> ...     k = elem[0]
> ...     d.addlist(k, elem)
> ...
> >>> d
> {'a': ['apple', 'ant', 'asp'], 'b': ['banana', 'boa'], 'o': ['orange',
> 'otter',
> 'onyx']}
> 
> 
> bookindex = dict()

(What's wrong with {}?)

> for pageno, page in enumerate(pages):
>     for word in page:
>         bookindex.addlist(word, pageno)

I'm -0 on the idea (where does it stop? when we have reimplemented
Perl?), and -1 on the name (it suggests adding a list).

It *is* a somewhat common idiom, but do we really need to turn all
idioms into method calls?  I think not -- only if the idiom is hard to
read in its natural form.

  bookindex = {}
  for pageno, page in enumerate(pages):
      for word in page:
          lst = bookindex.get(word)
          if lst is None:
              bookindex[word] = lst = []
          lst.append(pageno)

works for me.  (I think setdefault() was already a minor mistake -- by
the time I've realized it applies I have already written working code
without it.  And when using setdefault() I always worry about the
waste of the new empty list passed in each time that's ignored most
times.)

If you really want library support for this idiom, I'd propose adding
a higher-level abstraction that represents an index:

  bookindex = Index()
  for pageno, page in enumerate(pages):
      for word in page:
          bookindex.add(word, pageno)

What you're really doing here is inverting an index; maybe that idea
can be leveraged?

  bookindex = Index()
  bookindex.fill(enumerate(pages), lambda page: iter(page))

This would require something like

  class Index:
      def __init__(self):
          self.map = {}
      def fill(self, items, extract):
          for key, subsequence in items:
              for value in extract(subsequence):
                  self.map.setdefault(value, []).append(key)

Hm, maybe it should take a key function instead:

  bookindex = Index()
  bookindex.fill(enumerate(pages), lambda x: iter(x[1]), lambda x:
  x[0])

with a definition of

  class Index:
      def __init__(self):
          self.map = {}
      def fill(self, seq, getitems, getkey):
          for item in seq:
              key = getkey(item)
              for value in getitems(item):
                  self.map.setdefault(value, []).append(key)

Hmm...  Needs more work...  I don't like using extractor functions.
But I like addlist() even less.

--Guido van Rossum (home page: http://www.python.org/~guido/)



More information about the Python-Dev mailing list