Python 深入探究字典和集合的实现原理

字典和集合的实现原理

泛映射类型

只有可散列的数据类型才能用作这些映射里的键。

如果一个对象是可散列的,那么在这个对象的生命周期中,它的散列值是不变的,而且这个对象需要实现 __hash__()方 法。另外可散列对象还要有 __eq__()方法,这样才能跟其他键做比较。

因此,原子不可变数据类型是可散列的。用户自定义的类型的对象一般是可散列的,散列值就是id()的返回值,但如果其实现了__eq__()方法,并且方法中用到了这个对象的内部状态,那么只有当这些内部状态都不可变时,对象才是可散列的。

字典的常用构建方法:

>>> a = dict(one=1, two=2, three=3) 
>>> b = {'one': 1, 'two': 2, 'three': 3} 
>>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3])) 
>>> d = dict([('two', 2), ('one', 1), ('three', 3)]) 
>>> e = dict({'three': 3, 'one': 1, 'two': 2}) 
>>> a == b == c == d == e True

另外还有字典推导( dictcomp )式:

一些特殊的映射

defaultdict:处理找不到的键

在实例化一个 defaultdict 的时候,需要给构造方法提供 一个可调用对象,这个可调用对象会在__getitem__碰到找不到的键的时候被调用,让__getitem__返回某种默认值, 并且这个返回值和对应的键被对应起来。

这个用来生成默认值的可调用对象被存放在名为default_factory的实例属性中,这个属性只会在__getitem()中被调用,在其他方法(如get)中不会发挥作用。

特殊方法__missing__

当一个类继承了dict并且实现了方法__missing__时,在__getitem__碰到找不到的键的时候,Python 就会自动调用它, 而不是抛出一个 KeyError 异常。

class StrKeyDict0(dict):
    def __missing__(self, key):        
        if isinstance(key, str):
            raise KeyError(key)        
        return self[str(key)]
    def get(self, key, default=None):        
        try:            
            return self[key]   
        except KeyError:        
            return default
	def __contains__(self, key):    
        return key in self.keys() or str(key) in self.keys()

字典的变种

  • collections.OrderedDict:

    这个类型在添加键的时候会保持顺序,因此键的迭代次序总是一致的。

    OrderedDict 的 popitem 方法默认删除并返回的是字典里的最后一个元素,但是如果像 my_odict.popitem(last=False) 这样调用它,那么它删除并返回第一个被添加进去的元素。

  • collections.ChainMap:

    该类型可以容纳数个不同的映射对象,然后在进行键查找操作的时候,这些对象会被当作一个整体被逐个查找,直到键被找到为止。例如python解释器的变量查询规则如下:

    import builtins 
    pylookup = ChainMap(locals(), globals(), vars(builtins))
    
  • collections.Counter:

    用于实现计数器。

  • colllections.UserDict :

    供用户继承编写子类。

集合

集合中的元素必须是可散列的,所以集合中不能包含集合但是可以包含frozenset。

构建集合使用{},但构建空集要使用set()。

集合的常见操作:

  • 数学运算 &求交集,|求并集,-求差集,^求对称差集。
  • 比较运算符:a.isdisjoint(b)判断a与b是否不相交,in判断属于,>,>=,<,<=用于判断子集,a.issubset(b),a.issuperset(b),将可迭代的b转化为集合,然后进行判断。
  • 其他方法:add(e)添加元素e;discard(e)如果有,移出元素e;remove(e),移除元素e,若无抛出KeyError。

dict和set的实现原理

dict和set背后是通过散列技术实现的,因此查找的效率非常高。

这也带来了以下的一些影响:

  1. 键必须是可散列的:
    • 支持hash函数,通过hash函数应该得到一个不变的散列值;
    • 支持通过__eq__()来检测相等性;
    • 一致性:若hash(a) == hash(b)则必须要有 a == b。
  2. 内存开销巨大
  3. 键查询很快:几乎是常数时间访问
  4. 键的顺序取决于添加顺序;添加新键可能会改变已有键的顺序:由于散列冲突的处理

h(b)则必须要有 a == b。
2. 内存开销巨大
3. 键查询很快:几乎是常数时间访问
4. 键的顺序取决于添加顺序;添加新键可能会改变已有键的顺序:由于散列冲突的处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值