Python 2.5中增加的collections.defaultdict极大地减少了对dict的setdefault方法的需求。这个问题是为了我们的集体教育:
在今天的Python 2.6/2.7中,setdefault在哪些方面仍然有用? setdefault的哪些流行用例被collections.defaultdict所取代?
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'],}
其他回答
你可以说defaultdict用于在填充dict之前设置默认值,而setdefault用于在填充dict期间或之后设置默认值。
可能是最常见的用例:对项进行分组(在未排序的数据中,否则使用itertools.groupby)
# really verbose
new = {}
for (key, value) in data:
if key in new:
new[key].append( value )
else:
new[key] = [value]
# easy with setdefault
new = {}
for (key, value) in data:
group = new.setdefault(key, []) # key might exist already
group.append( value )
# even simpler with defaultdict
from collections import defaultdict
new = defaultdict(list)
for (key, value) in data:
new[key].append( value ) # all keys have a default already
有时您希望在创建字典后确保特定的键存在。Defaultdict在这种情况下不起作用,因为它只在显式访问上创建键。假设你使用一些带有许多头的HTTP-ish——有些是可选的,但你想要它们的默认值:
headers = parse_headers( msg ) # parse the message, get a dict
# now add all the optional headers
for headername, defaultvalue in optional_headers:
headers.setdefault( headername, defaultvalue )
我认为上面没有提到的另一个用例。 有时你会根据对象的id来保存一个缓存字典,其中主实例在缓存中,当缺少缓存时你想设置缓存。
return self.objects_by_id.setdefault(obj.id, obj)
当您总是希望每个不同的id保留一个实例时,无论每次如何获取obj,这都很有用。例如,当对象属性在内存中更新并延迟保存到存储中时。
从理论上讲,如果您有时想设置默认值,有时不想设置默认值,那么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.
当我想要OrderedDict中的默认值时,我使用setdefault()。没有一个标准的Python集合可以同时做到这两点,但是有一些方法可以实现这样的集合。
除了上述建议之外,如果您不想修改已经设置的值,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]