在Python 2.5中增加了collections.defaultdict
,极大地减少了使用dict
的setdefault
方法的需要。本问题是为了我们共同学习而提出的:
setdefault
在今天的Python 2.6 / 2.7中仍有哪些用途?collections.defaultdict
取代了哪些流行的setdefault
用例?
在Python 2.5中增加了collections.defaultdict
,极大地减少了使用dict
的setdefault
方法的需要。本问题是为了我们共同学习而提出的:
setdefault
在今天的Python 2.6 / 2.7中仍有哪些用途?collections.defaultdict
取代了哪些流行的setdefault
用例?defaultdict
对于在填充字典之前设置默认值很有用,而setdefault
则对于在填充之时或之后设置默认值很有用。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的协议并有许多头信息 -- 一些是可选的,但你想要默认值。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 )
我通常使用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)
它非常适合调整围绕接受关键字参数的函数的包装器中的参数。
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())
请注意,dict.get(key, nextID())
不足以满足我的要求,因为我需要稍后能够引用这些值。
intGen
是我创建的一个小类,它自动递增一个整数并返回其值。class intGen:
def __init__(self):
self.i = 0
def __call__(self):
self.i += 1
return self.i
如果有人知道使用 defaultdict
来完成这个任务的方法,我很愿意看到。
itertools.count().next
替换intGen
。 - AntimonymyDict.setdefault()
时,nextID()
的值都将递增,即使返回的值未被用作strID
。这种情况似乎有些浪费,并且说明了我对setdefault()
的一些不喜欢之处——即它总是评估其default
参数,无论它是否实际被使用。 - martineaudefaultdict
来实现:myDict = defaultdict(lambda: nextID())
。然后,在循环中使用 strID = myDict[myStr]
。 - musiphilmyDict = defaultdict(nextID)
? - forty_two像大多数回答所述,setdefault
或defaultdict
可以让您在键不存在时设置默认值。但是,我想指出关于setdefault
用例的一个小注意点。当Python解释器执行setdefault
时,即使键存在于字典中,它也会始终评估函数的第二个参数。例如:
In: d = {1:5, 2:6}
In: d
Out: {1: 5, 2: 6}
In: d.setdefault(2, 0)
Out: 6
In: d.setdefault(2, print('test'))
test
Out: 6
正如您所看到的,即使字典中已经存在2,print
也会被执行。这在您计划使用 setdefault
进行优化(例如用于记忆化
)时变得非常重要。如果将递归函数调用作为 setdefault
的第二个参数添加,它不会产生任何性能提升,因为 Python 将始终以递归方式调用该函数。
既然提到了记忆化,如果您考虑使用记忆化增强函数,则更好的选择是使用 functools.lru_cache 装饰器。lru_cache 更好地处理递归函数的缓存需求。
就像穆罕默德所说,有时只需要设置默认值的情况。一个很好的例子是一个数据结构首先被填充,然后进行查询。
考虑一棵 trie 树。在添加单词时,如果需要但不存在子节点,则必须创建以扩展 trie 树。在查询单词是否存在时,缺少的子节点表示该单词不存在,不应该创建它。
defaultdict 无法实现这一点。相反,必须使用带有 get 和 setdefault 方法的常规 dict。
setdefault
在有时需要设置默认值和有时不需要设置默认值的情况下仍然很方便。但在实际生活中,我还没有遇到这样的用例。>>> mydata = local()
>>> mydata.__dict__
{'number': 42}
>>> mydata.__dict__.setdefault('widgets', [])
[]
>>> mydata.widgets
[]
__dict__.setdefault
是一个相当有用的情况。setdefault
的必要性。不过,以下是解释:__dict__
属性中。恰好在创建对象后,__dict__
属性是可写的。它也是一个字典,而不是一个defaultdict
。一般情况下,对象作为defaultdict
具有__dict__
是不明智的,因为这将使每个对象都具有所有合法的标识符作为属性。因此,除非被认为没有用处,我无法预见任何Python对象的更改会摆脱__dict__.setdefault
,除非完全删除它。__dict__
实现上是一个dict
,而不是一个defaultdict
。 - Katrielsetdefault
在 Python 中保留,但现在它几乎没什么用,这很奇怪。 - Eli Benderskysetdefault
明确表示您正在通过可能存在或不存在的键分配给字典,并且如果它不存在,则希望创建具有默认值的字典:例如 d.setdefault(key,[]).append(value)
。在程序的其他地方,您执行 alist=d[k]
,其中 k 是计算出来的,如果 k 不在 d 中,则希望抛出异常(这可能需要使用 defaultdict 的 assert k in d
或甚至 if not ( k in d): raise KeyError
)。 - nigel222#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
(dict.setdefault
) 的一个缺陷是,每次给定一个不存在的键时(例如使用 ==
或 print
),defaultdict
对象都会创建一个新项。此外,defaultdict
类通常比 dict
类更少见,因此在序列化方面更加困难。
另外,我认为不应该通过函数或方法来改变对象,这样做是不合适的。
defaultdict(lambda l=[]: l)
来代替。 - Artyerget
而不是[...]
。调用get
不会导致默认对象的创建。 - undefined"""
d = {}
# To add a key->value pair, do the following:
d.setdefault(key, []).append(value)
# To retrieve a list of the values for a key
list_of_values = d[key]
# To remove a key->value pair is still easy, if
# you don't mind leaving empty lists behind when
# the last value for a given key is removed:
d[key].remove(value)
# Despite the empty lists, it's still possible to
# test for the existance of values easily:
if d.has_key(key) and d[key]:
pass # d has some values for key
# Note: Each value can exist multiple times!
"""
e = {}
print e
e.setdefault('Cars', []).append('Toyota')
print e
e.setdefault('Motorcycles', []).append('Yamaha')
print e
e.setdefault('Airplanes', []).append('Boeing')
print e
e.setdefault('Cars', []).append('Honda')
print e
e.setdefault('Cars', []).append('BMW')
print e
e.setdefault('Cars', []).append('Toyota')
print e
# NOTE: now e['Cars'] == ['Toyota', 'Honda', 'BMW', 'Toyota']
e['Cars'].remove('Toyota')
print e
# NOTE: it's still true that ('Toyota' in e['Cars'])
setdefault
返回值的例子。这是一种更简单的使用方式。 - Martlark
defaultdict
替换的主要用例。你能举个例子来说明第一段中的意思吗? - Eli Benderskyheaders = dict(optional_headers)
。对于默认值不全相等的情况,这样做是可行的。最终结果与先获取HTTP头然后设置未获取的默认值相同。如果您已经有了optional_headers
,那么这种方法非常实用。尝试我的两步代码并将其与您的进行比较,您会明白我的意思。 - Muhammad Alkarourinew.setdefault(key, []).append(value)
。该语句的作用是,如果字典new
中已存在键key
,则将值value
添加到该键对应的列表中;如果不存在,则创建一个新的键值对,键为key
,值为包含value
的列表。 - fmalinadefaultdict
比setdefault
更好(那么现在还有哪些用例呢?)我觉得很奇怪。此外,在我看来,ChainMap
可以更好地处理http
的示例。 - YvesgereY