键的次序取决于添加顺序,但是往字典里添加新键可能会改变已有键的顺序
无论何时往字典里添加新的键,Python 解释器都可能做出为字典扩容的决定。扩容导致的结果就是要新建一个更大的散列表,并把字典里已有的元素添加到新表里。这个过程中可能会发生新的散列冲突,导致新散列表中键的次序变化。要注意的是,上面提到的这些变化是否会发生以及如何发生,都依赖于字典背后的具体实现。
如果你在迭代一个字典的所有键的过程中同时对字典进行修改,那么这个循环很有可能会跳过一些键——甚至是跳过那些字典中已经有的键。
由此可知,不要对字典同时进行迭代和修改。如果想扫描并修改一个字典,最好分成两步来进行:
首先对字典迭代,以得出需要添加的内容,把这些内容放在一个新字典里;
迭代结束之后再对原有字典进行更新。
1.dict其它方法
d.__contains__(k) #检查 k 是否在 d 中 d.__setitem__(k,v) #实现 d[k] = v 操作,把 k 对应的值设为v d.default_factory #在 __missing__ 函数中被调用的函数,用以给未找到的元素设置值* d.__delitem__(k) del d[k] #移除键为 k 的元素 d.__getitem__(k) #让字典 d 能用 d[k] 的形式返回键 k 对应的值 d.__iter__() #获取键的迭代器 d.__len__() #可以用 len(d) 的形式得到字典里键值对的数量 d.__missing__(k) #当 __getitem__ 找不到对应键的时候,这个方法会被调用 d.move_to_end(k,[last])把键为 k 的元素移动到最靠前或者最靠后的位置(last的默认值是 True) d.__reversed__() #返回倒序的键的迭代器 d.__setitem__(k,v) #实现 d[k] = v 操作,把 k 对应的值设为v
2.键查询
有时候为了方便起见,就算某个键在映射里不存在,我们也希望能得到一个默认值。
有两个途径,一个是通过 defaultdict 这个类型而不是普通的 dict,另一个是给自己定义一个 dict 的子类,然后在子类中实现__missing__ 方法。
如果有一个类继承了 dict,然后这个继承类提供了__missing__ 方法,那么在 __getitem__ 碰到找不到的键的时候,Python 就会自动调用它,而不是抛出一个 KeyError 异常。
3.字典的变种
collections.OrderedDict
这个类型在添加键的时候会保持顺序,因此键的迭代次序总是一致的。OrderedDict 的 popitem 方法默认删除并返回的是字典里的最后一个元素。
collections.ChainMap
该类型可以容纳数个不同的映射对象,然后在进行键查找操作的时候,这些对象会被
当作一个整体被逐个查找,直到键被找到为止。
import builtins pylookup = ChainMap(locals(), globals(), vars(builtins))
collections.Counter
这个映射类型会给键准备一个整数计数器。每次更新一个键的时候都会增加这个计数器。
计算单词中各个字母出现的次数:
ct = collections.Counter('abracadabra') print(ct) #Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}) ct.update('aaaaazzz') print(ct) #Counter({'a': 10, 'z': 3, 'b': 2, 'r': 2, 'c': 1, 'd': 1}) l=ct.most_common(2) print(l) #[('a', 10), ('z', 3)]
colllections.UserDict
UserDict 是让用户继承写子类的。
值得注意的地方是,UserDict 并不是 dict 的子类,但是 UserDict 有一个叫作 data 的属性,是 dict 的实例,这个属性实际上是 UserDict 最终存储数据的地方。
下面StrKeyDict 都会把非字符串的键转换为字符串
import collections class StrKeyDict(collections.UserDict): def __missing__(self, key): if isinstance(key, str): raise KeyError(key) return self[str(key)] def __contains__(self, key): return str(key) in self.data def __setitem__(self, key, item): self.data[str(key)] = item