[Python-Dev] Counter proposal: multidict (was: Proposal: defaultdict) (original) (raw)

Ian Bicking ianb at colorstudy.com
Fri Feb 17 20:51:04 CET 2006


I really don't like that defaultdict (or a dict extension) means that x[not_found] will have noticeable side effects. This all seems to be a roundabout way to address one important use case of a dictionary with multiple values for each key, and in the process breaking an important quality of good Python code, that attribute and getitem access not have noticeable side effects.

So, here's a proposed interface for a new multidict object, borrowing some methods from Set but mostly from dict. Some things that seemed particularly questionable to me are marked with ??.

class multidict:

 def __init__([mapping], [**kwargs]):
     """
     Create a multidict:

     multidict() -> new empty multidict
     multidict(mapping) -> equivalent to:
         ob = multidict()
         ob.update(mapping)
     multidict(**kwargs) -> equivalent to:
         ob = multidict()
         ob.update(kwargs)
     """

 def __contains__(key):
     """
     True if ``self[key]`` is true
     """

 def __getitem__(key):
     """
     Returns a list of items associated with the given key.  If
     nothing, then the empty list.

     ??: Is the list mutable, and to what effect?
     """

 def __delitem__(key):
     """
     Removes any instances of key from the dictionary.  Does
     not raise an error if there are no values associated.

     ??: Should this raise a KeyError sometimes?
     """

 def __setitem__(key, value):
     """
     Same as:

         del self[key]
         self.add(key, value)
     """

 def get(key, default=[]):
     """
     Returns a list of items associated with the given key,
     or if that list would be empty it returns default
     """

 def getfirst(key, default=None):
     """
     Equivalent to:
         if key in self:
             return self[key][0]
         else:
             return default
     """

 def add(key, value):
     """
     Adds the value with the given key, so that
     self[key][-1] == value
     """

 def remove(key, value):
     """
     Remove (key, value) from the mapping (raising KeyError if not
     present).
     """

 def discard(key, value):
     """
     Remove like self.remove(key, value), except do not raise
     KeyError if missing.
     """

 def pop(key):
     """
     Removes key and returns the value; returns [] and does nothing
     if the key is not found.
     """

 def keys():
     """
     Returns all the keys which have some associated value.
     """

 def items():
     """
     Returns [(key, value)] for every key/value pair.  Keys that
     have multiple values will be returned as multiple (key, value)
     tuples.
     """

 def __len__():
     """
     Equivalent to len(self.items())

     ??: Not len(self.keys())?
     """

 def update(E, **kwargs):
     """
     if E has iteritems then::

         for k, v in E.iteritems():
             self.add(k, v)

     elif E has keys:

         for k in E:
             self.add(k, E[k])

     else:

         for k, v in E:
             self.add(k, v)

     ??: Should **kwargs be allowed?  If so, should it the values
     be sequences?
     """

 # iteritems, iterkeys, iter, has_key, copy, popitem, values, clear
 # with obvious implementations


More information about the Python-Dev mailing list