几个问题?
-
Python里的dict和set效率有多高?
-
为什么它们是无序的?
-
为什么并不是所有的Pythoon对象都可以当作dict的键或set里的元素?
-
为什么dict的键和set元素的顺序是根据它们被添加的次序而定的,以及为什么在映射对象的生命周期中,这个顺序并不是一成不变的?
-
为什么不应该在迭代循环dict或是set的同时往里添加元素?
字典的散列表
散列表是一个稀疏数组(总是有空白元素的数组)。
散列表里的单元通常叫做表元。dict的散列表中,每个键值对都占用一个表元,表元都有两部分,一个是对键的引用,一个是对值的引用。
Python会设法保证大概还有三分之一的表元是空的;
如果要把一个对象放入散列表,首先要计算这个元素的散列值。(Python会用到hash方法);
散列表算法

添加新元素和更新现有键值的操作几乎和上面一样;
前者在发现空表元时会放入一个新元素;对于后者,在找到对应的表元后,原表里的值对象会被替换成新值。
在插入新值时,Python可能会按照散列表的拥挤程度来决定是否要重新分配内存为它扩容。增加了散列表的大小,那散列值所占的位数和用作索引的位数都会增加,目的是为了减少发送散列冲突的概率。
dict的实现及优缺点【实际就是以空间换时间】
1、键必须是可散列的
可散列对象必须满足以下要求:
-
支持hash()函数,并通过__hash__()方法所得到的散列值是不变的;
-
支持通过__eq__()方法来检测相等性;
-
若a==b为真,则hash(a)==hash(b)也为真。
2、字典在内存上开销巨大
使用了散列表,而散列表又必须是稀疏的,导致空间上的效率低下。
3、键查询很快
字典类型有着巨大的内存开销,但它们提供了无视数据量大小的快速访问。
4、键的次序取决于添加顺序
当往dict里添加新键而又发生散列冲突的时候,新键可能会被安排存放到另一个位置。
5、往字典里添加新键可能会改变已有键的顺序
无论何时往字典里添加新的键,Python解释器都可能做出为字典扩容的决定。
扩容导致的结果就是要新建一个更大的散列表,并把字典里已有的元素添加到新表里。可能会发生新的散列冲突,导致新散列表中键的次序变化。
备注:
1、不要对字典同时进行迭代和修改
2、dict.keys()、dict.values()、dict.items()返回的是一个字典视图对象,不是列表。更像是集合,可以迭代。
example
# 尝试在迭代时去修改字典
for key, value in c.items(): if max_values == value: if key == ignore_word: del c[key]