

"""
默认字典-defaultdict
在Python字典中收集数据通常是很有用的。
在字典中获取一个 key 有两种方法, 第一种 get , 第二种 通过 [] 获取.
使用dict时，如果引用的Key不存在，就会抛出KeyError。如果希望key不存在时，返回一个默认值，就可以用defaultdict。
当我使用普通的字典时，用法一般是dict={},添加元素的只需要dict[element] =value即，调用的时候也是如此，
dict[element] = xxx,但前提是element字典里，如果不在字典里就会报错
这时defaultdict就能排上用场了，defaultdict的作用是在于，当字典里的key不存在但被查找时，
返回的不是keyError而是一个默认值，这个默认值是什么呢，下面会说

1、基础介绍
defaultdict([default_factory[, ...]])
返回一个新的类似字典的对象。 defaultdict是内置dict类的子类。它重载了一个方法并添加了一个可写的实例变量。
其余的功能与dict类相同，此处不再重复说明。
本对象包含一个名为default_factory的属性，构造时，第一个参数用于为该属性提供初始值，默认为 None。
所有其他参数（包括关键字参数）都相当于传递给 dict 的构造函数。
defaultdict 对象除了支持标准 dict 的操作，还支持以下方法作为扩展：
__missing__(key)
如果 default_factory 属性为 None，则调用本方法会抛出 KeyError 异常，附带参数 key。
如果 default_factory 不为 None，则它会被（不带参数地）调用来为 key 提供一个默认值，
这个值和 key 作为一对键值对被插入到字典中，并作为本方法的返回值返回。
如果调用 default_factory 时抛出了异常，这个异常会原封不动地向外层传递。
在无法找到所需键值时，本方法会被 dict 中的 __getitem__() 方法调用。
无论本方法返回了值还是抛出了异常，都会被 __getitem__() 传递。
注意，__missing__() 不会 被 __getitem__() 以外的其他方法调用。
意味着 get() 会像正常的 dict 那样返回 None，而不是使用 default_factory。
"""
from collections import defaultdict

"""
2、示例介绍
使用 list 作为 default_factory，很轻松地将（键-值对组成的）序列转换为（键-列表组成的）字典
"""
s  = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = defaultdict(list)
for k, v in s:
    d[k].append(v)
print(sorted(d.items()))

"""
当每个键第一次遇见时，它还没有在字典里面，所以自动创建该条目，即调用default_factory方法，
返回一个空的 list。 list.append() 操作添加值到这个新的列表里。当再次存取该键时，就正常操作，list.append() 
添加另一个值到列表中。这个计数比它的等价方法dict.setdefault()要快速和简单：
"""
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = {}
for k, v in s:
    d.setdefault(k, []).append(v)
print(sorted(d.items()))
# 设置 default_factory为int，使defaultdict用于计数（类似其他语言中的 bag或multiset）：
s = 'mississippi'
d = defaultdict(int)
for k in s:
    d[k] += 1
print(sorted(d.items()))

# 设置 default_factory 为 set 使 defaultdict 用于构建 set 集合：
s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
d = defaultdict(set)
for k, v in s:
    d[k].add(v)
print(sorted(d.items()))
print(d['aaa'])

