1.3.2 defaultdict
dict的setdefault()方法在key不存在时会建立一个默认值。与此相反,defaultdict会在初始化时指定默认值。
import collections
def default_factory():
return 'defaultvalue'
d = collections.defaultdict(default_factory, foo='bar')
print 'd:', d
print 'foo =>', d['foo']
print 'bar =>', d['bar']
执行结果:
# ./collections_defaultdict.py
d: defaultdict(<function default_factory at 0xb77d2e2c>,{'foo': 'bar'})
foo => bar
bar => default value
注意,所有key的默认值都是一样,这点未必有setdefault灵活。但是默认值是容器(list, set 等)甚至是int的时候,就很好用,请看后面标准库中的应用。
先看定义:class collections.defaultdict([default_factory[, ...]]) 。defaultdict重载了__missing__(),增加了一个可写的实例变量default_factory。如果default_factory为空或者None,和dict一样找不到key时报异常KeyError。指定default_factory找不到值会调用__getitem__()。所以get()和普通字典一样。
另外copy和fromkeys的返回也不一致。
>>> import collections
>>> d1 = {}
>>> d2 = collections.defaultdict()
>>> d1.fromkeys([1,2])
{1: None, 2: None}
>>> d2.fromkeys([1,2])
defaultdict(None, {1: None, 2: None})
>>> d1.copy()
{}
>>> d2.copy()
defaultdict(None, {})
下面是标准库中的实例:
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3),('blue', 4), ('red', 1)]
>>> from collections import defaultdict
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3),('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
... d[k].append(v)
...
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
用dict.setdefault()也可以达到类似效果:
>>> d = {}
>>> for k, v in s:
... d.setdefault(k,[]).append(v)
...
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
设置为int可以用来计数。和其他语言中的bag或multiset类似。
>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
... d[k] += 1
...
>>> d.items()
[('i', 4), ('p', 2), ('s', 4), ('m', 1)]
上例有个前提:int()返回的值是0.
另外一种创建常量函数的用法如下,使用了itertools.repeat()。
>>> def constant_factory(value):
... return itertools.repeat(value).next
>>> d = defaultdict(constant_factory('<missing>'))
>>> d.update(name='John', action='ran')
>>> '%(name)s %(action)s to %(object)s' % d
'John ran to <missing>
设置default_factory为set可以构建集合字典:
>>> def constant_factory(value):
... return itertools.repeat(value).next
>>> d = defaultdict(constant_factory('<missing>'))
>>> d.update(name='John', action='ran')
>>> '%(name)s %(action)s to %(object)s' % d
'John ran to <missing>