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

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


当前回答

我通常使用setdefault作为关键字参数字典,例如在这个函数中:

def notify(self, level, *pargs, **kwargs):
    kwargs.setdefault("persist", level >= DANGER)
    self.__defcon.set(level, **kwargs)
    try:
        kwargs.setdefault("name", self.client.player_entity().name)
    except pytibia.PlayerEntityNotFound:
        pass
    return _notify(level, *pargs, **kwargs)

它非常适合在包装器中围绕接受关键字参数的函数调整参数。

其他回答

正如Muhammad所说,在某些情况下,您只是偶尔希望设置默认值。一个很好的例子是数据结构,首先填充,然后查询。

考虑一个例子。在添加单词时,如果需要子节点但不存在,则必须创建子节点以扩展树。在查询单词是否存在时,缺少子节点表示该单词不存在,不应该创建它。

defaultdict不能这样做。相反,必须使用带有get和setdefault方法的常规dict。

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

#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'],}

从理论上讲,如果您有时想设置默认值,有时不想设置默认值,那么setdefault仍然很方便。在现实生活中,我还没有遇到过这样的用例。

然而,一个有趣的用例来自标准库(Python 2.6, _threadinglocal.py):

>>> mydata = local()
>>> mydata.__dict__
{'number': 42}
>>> mydata.__dict__.setdefault('widgets', [])
[]
>>> mydata.widgets
[]

我会说使用__dict__。Setdefault是一个非常有用的例子。

编辑:碰巧,这是标准库中唯一的示例,并且它在注释中。因此,它可能不足以证明setdefault的存在。不过,这里有一个解释:

Objects store their attributes in the __dict__ attribute. As it happens, the __dict__ attribute is writeable at any time after the object creation. It is also a dictionary not a defaultdict. It is not sensible for objects in the general case to have __dict__ as a defaultdict because that would make each object having all legal identifiers as attributes. So I can't foresee any change to Python objects getting rid of __dict__.setdefault, apart from deleting it altogether if it was deemed not useful.

除了上述建议之外,如果您不想修改已经设置的值,setdefault可能会很有用。例如,当你有重复的数字,你想把它们当作一组。在这种情况下,如果遇到已设置的重复键,则不会更新该键的值。您将保留第一次遇到的值。就好像你只迭代/更新重复的键一次。

下面是一个记录排序列表中键/元素索引的代码示例:

nums = [2,2,2,2,2]
d = {}
for idx, num in enumerate(sorted(nums)):
    # This will be updated with the value/index of the of the last repeated key
    # d[num] = idx # Result (sorted_indices): [4, 4, 4, 4, 4]
    # In the case of setdefault, all encountered repeated keys won't update the key.
    # However, only the first encountered key's index will be set 
    d.setdefault(num,idx) # Result (sorted_indices): [0, 0, 0, 0, 0]

sorted_indices = [d[i] for i in nums]

我经常使用setdefault,在字典中设置默认值(!!)通常是os。环境字典:

# Set the venv dir if it isn't already overridden:
os.environ.setdefault('VENV_DIR', '/my/default/path')

简单点说,是这样的:

# Set the venv dir if it isn't already overridden:
if 'VENV_DIR' not in os.environ:
    os.environ['VENV_DIR'] = '/my/default/path')

值得注意的是,你也可以使用结果变量:

venv_dir = os.environ.setdefault('VENV_DIR', '/my/default/path')

但与违约之前相比,这已经不那么必要了。