collections.abc 模块中有 Mapping 和 MutableMapping 这两个抽象类,他们的做用是为dict和其余相似的类型定义形式接口。python
标准库里全部映射类型都是利用dict来实现的,所以他们有个共同的限制,只有可散列的数据类型才能用做这些映射里的键。算法
可散列的数据类型:在这个对象的生命周期中,他的散列值是不变的,并且这个对象须要实现__hash__()方法,还要有__eq__()方法。数组
▲ 原子不可变数据类型(str、bytes和数值类型)、frozenset都是可散列类型。app
▲ 只有当一个元组包含的全部元素都是可散列类型的状况下,它才是可散列的。函数
字典提供了多种构造方法:spa
>>> a = dict(name='Li', sex='girl') >>> b = {'name':'Li', 'sex':'girl'} >>> c = dict(zip(['name','sex'], ['Li','girl'])) >>> d = dict([('name':'Li'), ('sex':'girl')]) >>> e = dict({'name':'Li', 'sex':'girl'}) >>> a == b == c == d == e True
2.一、字典推导code
从任何以键值对做为元素的可迭代对象中构建出字典。对象
>>> DIAL_CODE = [ ... (86,'China'), ... (1,'United States'), ... ] >>> country_code = {country:code for code,country in DIAL_CODE} {'China': 86, 'United States': 1} >>> {country:code for country,code in country_code.items() if code > 50} {'China': 86}
2.二、用setdefault处理找不到的键blog
在不进行二次查找的状况下更新列表继承
my_dict.setdefault(key, []).append(new_value) # 等于 if key not in my_dict: my_dict[key] = [] my_dict[key].append(new_value)
某个键在映射中不存在时,咱们也但愿经过这个键读取值的时候能获得一个默认值。
可使用defaultdict类型,或者自定义一个dict的子类,实现__missing__方法。
▲、在实例化一个defaultdict的时候,须要给构造方法提供一个可调用对象,这个可调用对象会在__getitem__找不到键的时候被调用,让__getitem__返回某种默认值。
如:dd = defaultdict(list) , dd['new_key']
若是new_key在dd中不存在,表达式dd['new_key']会按以下步骤执行:
(1)、调用list() 创建一个新列表。
(2)、把这个新列表做为值,‘new_key’做为键,放到dd中。
(3)、返回这个列表的引用。
▲、这个用来生成默认值 list 的可调用对象存放在名为 default_factory 的实例属性里。
▲、若是在建立defaultdict时没有指定 default_factory ,查询不存在键会触发 keyError 。
▲、defaultdict 里的 default_factory ,只会在__getitem__里被调用(dd[k]),而dd.get(k)则会返回None。
特殊方法__missing__,只会被__getitem__调用。
提供__missing__方法对get或者__contains__(in 运算符会用到这个方法)这些方法的使用没有影响。
collections.OrderedDict:添加键的时候后会保持顺序
>>> d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2} >>> OrderedDict(sorted(d.items(), key=lambda t: t[0])) OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])
collections.ChainMap:容纳不一样的映射对象,查找操做时,这些对象被看成一个总体被逐个查找。
collections.Counter:整数计数器。 元素被存储为字典键,它们的计数被存储为字典值。
collections.USerDict :让用户继承写子类。对一个字典对象的封装。其实例的内容保存在一个普通的字典当中,能够经过 UserDict 实例的属性 data 访问。
types模块引入了一个封装类名叫MappingProxyType。若是给这个类一个映射,它会返回一个只读的映射视图。
>>> from types import MappingProxyType >>> d = {'1':'one'} >>> d_proxy = MappingProxyType(d) >>> d_proxy mappingproxy({'1': 'one'}) >>> d_proxy['1'] 'one' >>> d_proxy['2'] = 'two' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'mappingproxy' object does not support item assignment >>> d['2'] = 'two' >>> d_proxy mappingproxy({'2': 'two', '1': 'one'})
集合的本质是许多惟一对象的汇集。因此,集合能够用于去重。
集合中的元素必须是可散列的,set类型自己是不可散列的,可是forzenset能够。因此能够建立一个包含不一样frozenset的set。
空集合:set()
集合一样有属于他的集合推导。
>>> from unicodedata import name >>> {chr(i) for i in range(32,256) if 'SIGN' in name(chr(i),'')} {'\xa2', '\xac', '§', '±', '\xa9', '\xb5', '\xae', '°', '$', '\xa3', '=', '+', '¤', '%', '÷', '<', '\xa5', '\xb6', '>', '#', '×'}
散列表是一个稀疏数组(老是有空白元素的数组)。散列表里的单元叫作表元。
在dict的散列表中,每个键值对都占用一个表元,每一个表元都有两个部分,一个是对键的引用,另外一个是对值得引用。
全部表元的大小一致,因此能够经过偏移量来读取某个表元。
Python会设法保证大概还有三分之一的表元是空的,在快要达到阈值的时候,原有的散列表会被复制到一个更大的空间里面。
若是要把一个对象放入散列表,那么首先要计算这个元素键的散列值。
内置的hash()方法用于全部内置对象,自定义对象调用hash()实际上运行自定义的__hash__。
若是两个对象在比较时是相等的,那他们的散列值必须相等。如(1 == 1.0)
▲ 散列值在索引空间中尽可能分散开,越是类似的但不相等的对象,散列值的差异应该越大。如(1.0001和1.0002)
散列表算法:为了获取my_dict[search_key]的值
(1)首先调用hash(search_key)计算search_key的散列值,把这个值最低几位数字当作偏移量,在散列表里查找表元。
(2)若找到的表元是空的,抛出KeyError异常
(3)若不为空,表元里会有一对found_key:found_value。进行检验search_key == found_key是否为真
(4)相等则返回found_value。不相等则称为散列冲突。
为了解决散列冲突,算法会在散列值中另外再取几位通过计算处理,把新获得的数字再当作索引来寻找表元。
一个可散列对象必须知足如下条件:
(1)支持hash()函数,而且经过__hash__()方法获得的散列值是不变的。
(2)经过__eq__()方法检测相等性。
(3)若a == b为真,则hash(a) == hash(b)也为真。
全部由用户自定义的对象默认都是可散列的。由于他们的散列值由id()来获取,并且他们都不相等。
▲ 字典在内存中开销巨大,典型的空间换时间。
▲ 键的次序取决于添加顺序
▲ 往字典添加新键可能会改变已有键的顺序(字典扩容决定)
set的实现:也依赖散列表,散列表里存放的只有元素的引用