collections模块之defaultdict

1,321 阅读3分钟

默认字典defaultdict是字典dict的一个子类,第一个参数为default_factory属性提供初始值,默认为None。它覆盖一个方法并添加一个可写的实例变量。其他功能和普通的dict相同,但是会为不存在的键提供默认值,从而避免KeyError异常。

1 单值映射字典中的使用

1.1 初始化时的情形

初始化之前先来看一看普通字典的情形

一般的dict会导致KeyError异常

count = {}
count['apple']
count['cherry']
print(count)

result:

Traceback (most recent call last):
  File "D:/interview/interview/22.py", line 2, in <module>
    count['apple']
KeyError: 'apple'

1.1.1 类型名称作为初始化时的参数

from collections import defaultdict
​
count = defaultdict(int)
count['apple']
count['cherry']
print(count)

result:

defaultdict(<class 'int'>, {'apple': 0, 'cherry': 0})

1.1.2 可调用函数作为初始化时的参数

def zero():
    return 0
​
​
count = defaultdict(zero)
count['apple']
count['cherry']
print(count)

result:

defaultdict(<function zero at 0x0000020D4DE55048>, {'apple': 0, 'cherry': 0})

1.2 更新时的情形

继承字典的所有方法,默认字典在初始化时必须指定字典的默认值

from collections import defaultdict
​
dic = defaultdict(dict)
dic["k1"].update({"asdsa":"123"})
print(dic)

result:

defaultdict(<class 'dict'>, {'k1': {'asdsa': '123'}})

字典dic在定义的时候就已经定义了值为字典类型,所以即使字典中没有k1这个键,仍然可以执行字典的update方法。这种操作方式在普通的字典中会报错

2 多值映射字典的情形

一般而言,字典就是一个键对应一个单值的映射,如果想要一个键映射多个值,可以将多个值放到容器中。

2.1 初始化时的情形

2.1.1 普通字典的操作

dict1 = {
    'a': [1, 2, 3],
    'b': [4, 5]
}
dict2 = {
    'a': {1, 2, 3},
    'b': {4, 5}
}

至于具体使用列表还是集合取决于实际需要。如果想要保持元素的插入顺序那就使用列表,反之则使用集合即可。

2.1.2 使用默认字典的操作

from collections import defaultdict
​
dict1 = defaultdict(list)
dict1['a'].append(1)
dict1['a'].extend([2, 3])
dict1['b'].extend([4, 5])
​
dict2 = defaultdict(set)
dict2['a'].add(1)
dict2['a'].update([2, 3])
dict2['b'].update([4, 5])
print(f'dict1===={dict1}')
print(f'dict2===={dict2}')

result:

dict1====defaultdict(<class 'list'>, {'a': [1, 2, 3], 'b': [4, 5]})
dict2====defaultdict(<class 'set'>, {'a': {1, 2, 3}, 'b': {4, 5}})

使用defaultdict需要注意的一点,defaultdict会为不存在的键也创建映射实体(其实就是值)。如果你不需要这个特性,可以在普通字典上使用setdefault()方法进行替代

2.1.3 使用setdefault()方法进行替代defaultdict

dict1 = {}
dict1.setdefault('a', []).append(1)
dict1.setdefault('a', []).extend([2, 3])
dict1.setdefault('b', []).extend([4, 5])
print(f'dict1===={dict1}')

result:

dict1===={'a': [1, 2, 3], 'b': [4, 5]}

2.2 更新时的情形

2.2.1 普通字典的操作

一般来讲,创建一个多值映射字典是很简单的。但是选择自己实现的话则在进行值的初始化的时候会显得有点麻烦

d = {}
pairs = [('banana', 3), ('apple', 4), ('pear', 1), ('orange', 2), ('banana', 4), ('pear', -1),]
for key, value in pairs:
    if key not in d:
        d[key] = []
    d[key].append(value)
print(d)

result:

{'banana': [3, 4], 'apple': [4], 'pear': [1, -1], 'orange': [2]}

2.2.2 默认字典的操作

from collections import defaultdict
​
d = defaultdict(list)
pairs = [('banana', 3), ('apple', 4), ('pear', 1), ('orange', 2), ('banana', 4), ('pear', -1),]
for key, value in pairs:
    d[key].append(value)
print(d)

result:

defaultdict(<class 'list'>, {'banana': [3, 4], 'apple': [4], 'pear': [1, -1], 'orange': [2]})

可以看到,使用defaultdict会使得代码更加简洁