![](https://secure.gravatar.com/avatar/dbdddb64dc47a7853e836edfed6b1f3f.jpg?s=120&d=mm&r=g)
Guido van Rossum wrote:
A bunch of Googlers were discussing the best way of doing the following (a common idiom when maintaining a dict of lists of values relating to a key, sometimes called a multimap):
if key not in d: d[key] = [] d[key].append(value)
An alternative way to spell this uses setdefault(), but it's not very readable:
d.setdefault(key, []).append(value)
and it also suffers from creating an unnecessary list instance. (Timings were inconclusive; the approaches are within 5-10% of each other in speed.)
My conclusion is that setdefault() is a failure -- it was a well-intentioned construct, but doesn't actually create more readable code.
Google has an internal data type called a DefaultDict which gets passed a default value upon construction. Its __getitem__ method, instead of raising KeyError, inserts a shallow copy (!) of the given default value into the dict when the value is not found. So the above code, after
d = DefaultDict([])
can be written as simply
d[key].append(value)
Using a shallow copy of the default seems a bit too magical to me. How would this be done? Via copy.copy? And passing [] to the constructor of dict has a different meaning already. Fetching the default via a static/class method would solve both problems: class default_dict(dict): def __getitem__(self, key): if key in self: return dict.__getitem__(self, key) else: default = self.getdefault() self[key] = default return default class multi_map(default_dict): @staticmethod def getdefault(self): return [] class counting_dict(default_dict): @staticmethod def getdefault(self): return 0
[...]
Bye, Walter Dörwald