https://zhuanlan.zhihu.com/p/187917186
容器(collections)是Python附带一个模块,它包含许多容器数据类型,今天先拿出defaultdict来说。
dict在python中是非常常见的一种数据类型。
colours = (
(‘Yasoob’, ‘Yellow’),
(‘Ali’, ‘Blue’),
(‘Arham’, ‘Green’),
)
dict = {}
for name, colour in colours:
dict[name] = colour
print(dict)
#output: {‘Yasoob’: ‘Yellow’, ‘Ali’: ‘Blue’, ‘Arham’: ‘Green’}
以上是dict的最常见用法,构造 键-值,但是它的缺陷是碰到没有遇到的键,就会报错
print(dict[‘bob’])
#output:KeyError: ‘bob’
这时候defaultdict就能派上用场了。
classcollections.defaultdict([default_factory[,…]])
defaultdict 是内置 dict 类的子类。它重载了一个方法并添加了一个可写的实例变量。其余的功能与 dict 类相同。
本对象包含一个名为 default_factory 的属性,构造时,第一个参数用于为该属性提供初始值,默认为 None。所有其他参数(包括关键字参数)都相当于传递给 dict 的构造函数。
根据定义,defaultdic只是比dict多了一个方法,而这个方法就是__missing__, 这个方法与default_factory有关。
如果 default_factory 属性为 None,则调用本方法会抛出 KeyError 异常,附带参数 key。
如果 default_factory 不为 None,则它会被(不带参数地)调用来为 key 提供一个默认值,这个值和 key 作为一对键值对被插入到字典中,并作为本方法的返回值返回。
default_factory
本属性由__missing__()方法来调用。如果构造对象时提供了第一个参数,则本属性会被初始化成那个参数,如果未提供第一个参数,则本属性为None。
default_factory可以为很多类型,list、set、str都可以,如果key不存在,返回为默认值。
dict1 = defaultdict(int)
dict2 = defaultdict(set)
dict3 = defaultdict(str)
dict4 = defaultdict(list)
print(dict1[1])
print(dict2[1])
print(dict3[1])
print(dict4[1])
output:
0 int的默认值
set() set的默认值
str的默认值
[] list的默认值
List
使用 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(d)
output:
defaultdict(<class ‘list’>, {‘yellow’: [1, 3], ‘blue’: [2, 4], ‘red’: [1]})
Int
设置 default_factory 为 int,使 defaultdict 用于计数(类似其他语言中的 bag 或 multiset):
str = ‘chinese’
d = defaultdict(int)
for k in str:
d[k] += 1
print(d)
output:
defaultdict(<class ‘int’>, {‘c’: 1, ‘h’: 1, ‘i’: 1, ‘n’: 1, ‘e’: 2, ‘s’: 1})
当一个字母首次遇到时,它会查询失败,则 default_factory 会调用 int() 来提供一个整数 0 作为默认值。后续的自增操作建立起对每个字母的计数。
Set
设置 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(d)
output:
defaultdict(<class ‘set’>, {‘red’: {1, 3}, ‘blue’: {2, 4}})
Lambda
Lambda函数更为灵活的指定默认值,可以为任意值。
strings = ‘chinese’
counts = defaultdict(lambda: 0)
for i in strings:
counts[i] +=1
print(counts)
output:
defaultdict(<function at 0x7fe1b1b3d170>, {‘c’: 1, ‘h’: 1, ‘i’: 1, ‘n’: 1, ‘e’: 2, ‘s’: 1})
#和int一样的效果
test = defaultdict(lambda : ‘hello’)
test[1]
test[2] = ‘two’
print(test)
output:
defaultdict(<function at 0x7fe338b11170>, {1: ‘hello’, 2: ‘two’})
Tips:
之前的输出都是连带着defaultdict里default_factory都输出了,但是一般没有必要,只需要使用item。
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(d)
print(d.items())
output:
defaultdict(<class ‘set’>, {‘red’: {1, 3}, ‘blue’: {2, 4}})
dict_items([(‘red’, {1, 3}), (‘blue’, {2, 4})])