Python 2.5中增加的collections.defaultdict极大地减少了对dict的setdefault方法的需求。这个问题是为了我们的集体教育:

在今天的Python 2.6/2.7中,setdefault在哪些方面仍然有用? setdefault的哪些流行用例被collections.defaultdict所取代?


当前回答

我重写了公认的答案,并为新手提供了方便。

#break it down and understand it intuitively.
new = {}
for (key, value) in data:
    if key not in new:
        new[key] = [] # this is core of setdefault equals to new.setdefault(key, [])
        new[key].append(value)
    else:
        new[key].append(value)


# easy with setdefault
new = {}
for (key, value) in data:
    group = new.setdefault(key, []) # it is new[key] = []
    group.append(value)



# even simpler with defaultdict
new = defaultdict(list)
for (key, value) in data:
    new[key].append(value) # all keys have a default value of empty list []

另外,我将这些方法分类为参考:

dict_methods_11 = {
            'views':['keys', 'values', 'items'],
            'add':['update','setdefault'],
            'remove':['pop', 'popitem','clear'],
            'retrieve':['get',],
            'copy':['copy','fromkeys'],}

其他回答

我认为上面没有提到的另一个用例。 有时你会根据对象的id来保存一个缓存字典,其中主实例在缓存中,当缺少缓存时你想设置缓存。

return self.objects_by_id.setdefault(obj.id, obj)

当您总是希望每个不同的id保留一个实例时,无论每次如何获取obj,这都很有用。例如,当对象属性在内存中更新并延迟保存到存储中时。

Defaultdict在默认值是静态时很好,就像一个新列表,但如果它是动态的,就不那么好了。

例如,我需要一个字典来映射字符串到唯一的整数。Defaultdict (int)将始终使用0作为默认值。同样,defaultdict(intGen())总是生成1。

相反,我用了一个普通的词典:

nextID = intGen()
myDict = {}
for lots of complicated stuff:
    #stuff that generates unpredictable, possibly already seen str
    strID = myDict.setdefault(myStr, nextID())

注意这个词典。get(key, nextID())是不够的,因为我需要能够在以后引用这些值。

intGen是我构建的一个小类,它自动递增int并返回它的值:

class intGen:
    def __init__(self):
        self.i = 0

    def __call__(self):
        self.i += 1
    return self.i

如果有人有办法做到这一点与defaultdict,我很乐意看到它。

[编辑]大错特错!setdefault总是会触发long_computation,因为Python很急切。

扩展塔特尔的答案。对我来说,最好的用例是缓存机制。而不是:

if x not in memo:
   memo[x]=long_computation(x)
return memo[x]

这需要3行和2到3次查找,我很乐意这样写:

return memo.setdefault(x, long_computation(x))

setdefault()的不同用例是当您不想覆盖已经设置的键的值时。Defaultdict会覆盖,而setdefault()不会。对于嵌套字典,更常见的情况是,只有在键尚未设置时才设置默认值,因为您不想删除当前子字典。这就是使用setdefault()的时候。

使用defaultdict的示例:

>>> from collection import defaultdict()
>>> foo = defaultdict()
>>> foo['a'] = 4
>>> foo['a'] = 2
>>> print(foo)
defaultdict(None, {'a': 2})

Setdefault不会覆盖:

>>> bar = dict()
>>> bar.setdefault('a', 4)
>>> bar.setdefault('a', 2)
>>> print(bar)
{'a': 4}

我喜欢这里给出的答案:

http://stupidpythonideas.blogspot.com/2013/08/defaultdict-vs-setdefault.html

简而言之,决策(在非性能关键型应用程序中)应该基于你想如何处理下游空键的查找(即KeyError与默认值)。