1、自动处理缺失的键
在字典高级用法(一)中介绍过自动处理缺失的键的第一种方法是使用defaultlist对象,现在我们接着介绍第二种方法,使用__missing__方法。
映射处理缺失键的底层逻辑在于__missing__方法中。dict基类本身没有定义这个方法,但是如果dict子类定义了这个方法,那么dict.__getitem__找不到键时将会调用__missing__方法,不抛出KeyError。示例如下
class DemoDict(dict): # 继承dict
def __missing__(self, key):
if isinstance(key, str):
raise KeyError(key) # 检查key是不是str类型,如果是,并且找不到键则抛出异常
return self[str(key)] # 将key转成str类型,查找字符串键
def get(self, key, default=None):
try:
return self[key] # get方法委托__getitem__,通过self[key]查找键,让__miss__发挥作用
except KeyError:
return default
def __contains__(self, key):
return key in self.keys() or str(key) in self.keys()
d = DemoDict([('2', 'two'), ('4', 'four')])
print(d['2']) # two
print(d[4]) # four
print(d['1']) # KeyError: '1'
print(d.get('2')) # two
print(d.get('4')) # four
print(d.get('1')) # None
print(d.get('1', 'N/A')) # N/A
讲到这里,大概明白字典通过key获取value的底层工作流程了吧,其实这里用户自定义映射类型最好继承collections.UserDict类,而不要继承dict类。上面继承dict类是为了说明内置dict.__getitem__方法支持__missing__。
2、dict变体
collections.OrderedDict
自Python 3.6 起,内置的 dict 也保留键的顺序。使⽤ OrderedDict 最主要的原因是编写与早期 Python 版本兼容的代码。 不过,dict 和 OrderedDict 之间还有⼀些差异,Python ⽂档中有说明,摘录如下(根据日常使用频率,顺序有调整)。
- OrderedDict 的等值检查考虑顺序
- OrderedDict 的 popitem() 方法签名不同,可通过⼀个可选 参数指定移除哪⼀项。
- OrderedDict 多了⼀个 move_to_end() ⽅法,便于把元素的位置移到某⼀端。 常规的 dict 主要⽤于执⾏映射操作,插⼊顺序是次要的。
- OrderedDict 的目的是方便执行重新排序操作,空间利⽤率、 迭代速度和更新操作的性能是次要的。
- 从算法上看,OrderedDict 处理频繁重新排序操作的效果比 dict 好,因此适合⽤于跟踪近期存取情况(例如在 LRU 缓存 中)。
collections.ChainMap
ChainMap实例存放一组映射,可作为一个整体来搜索。查找操作按照输入映射在构造函数调用中出现的顺序执行,一旦在某个映射中找到指定的键,旋即结束。比如:
d1 = dict(a=1, b=3)
d2 = dict(a=2, b=4, c=6)
from collections import ChainMap
chain = ChainMap(d1, d2)
print(chain['a']) # 1
print(chain['c']) # 6
ChainMap实例不复制输入映射,而是存放映射的引用。ChainMap的更新和插入操作只影响第一个输入映射。比如(接上面案例):
chain['c'] = -1
print(d1) # {'a': 1, 'b': 3, 'c': -1}
print(d2) # {'a': 2, 'b': 4, 'c': 6}
collections.Counter
这是一种对键计数的映射。更新现有键,计数随之增加。可用于统计可哈希对象的实例数量,或者作为多重集使用。Counter实现了组合计数的+和-运算,以及其他一些有用的方法,例如most_common([n])。该方法返回一个有序元组列表,对应前n个计数值最大的项及其数量。比如下面使用Counter统计文本中字的数量。
text = "只因你太美你实在是太美"
from collections import Counter
counter = Counter(text)
print(counter) # Counter({'你': 2, '太': 2, '美': 2, '只': 1, '因': 1, ',': 1, '实': 1, '在': 1, '是': 1})
counter.update('哦贝贝')
print(counter) # Counter({'你': 2, '太': 2, '美': 2, '贝': 2, '只': 1, '因': 1, '实': 1, '在': 1, '是': 1, '哦': 1})
print(counter.most_common(3)) # [('你', 2), ('太', 2), ('美', 2)]
shelve.Shelf
标准库中的 shelve 模块持久存储字符串键与(以 pickle ⼆进制格式序列化的)Python 对象之间的映射,这部分这里不作太多介绍,感兴趣可以去看Python文档。