1 collections 模块
python 为我们提供了四种基本的容器数据类型 list,tuple,dict,set。在大部分处理集合类型数据的应用场景,这四种数据结构都能轻松胜任。但是在处理大量数据和处理复杂数据元素运算的时候,这四中数据结构明显功能单一,且运算效率较低。python标准库为我们提供了collections包,里面提供很多功能强大的容器类型,熟练掌握这些容器类型,有助于提高我们的代码质量。这里主要介绍如下几种数据结构。
- namedtuple
- OrderedDict
- defaultdict
2 namedtuple
2.1简介
namedtuple是一个函数,创建一个自定义的tuple对象,规定tuple元素个数以及其对应的属性,可以根据属性而不是索引来访问,具有tuple的不变性,又可以根据属性来引用。创建的namedtuple是tuple类型的子类。
In [2]: from collections import namedtuple
In [3]: Point = namedtuple('Ponit',['x','y'])
In [4]: p = Point(1,2)
In [5]: p.x
Out[5]: 1
In [6]: p.y
Out[6]: 2
In [7]: type(p)
Out[7]: __main__.Ponit
In [8]: isinstance(p,tuple)
Out[8]: True
In [9]: p.x=5
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-9-c7ca42e996c7> in <module>()
----> 1 p.x=5
AttributeError: can't set attribute
2.2 自带描述信息
- 单纯的看一个元组的信息,我们很难看出元组以及元组每一项所表示的含义,采用namedtuple后,相当于给元组增加了文档描述。
- namedtuple实例没有对象字典,是一个轻量级数据结构,与普通元组相比并不需要更多内存。这使得他们比字典更快。
下面代码清楚的描述了一个圆的信息,circle相比较于circle2就要清楚太多了。
In [11]: Circle = namedtuple('Circle',['point','r'])
In [12]: circle = Circle(p,'5')
In [13]: circle
Out[13]: Circle(point=Ponit(x=1, y=2), r='5')
In [14]: circle.point.x
Out[14]: 1
In [15]: circle.point.y
Out[15]: 2
In [16]: circle.r
Out[16]: '5'
In [17]: circle2 = ((1,2),5)
In [18]: circle2
Out[18]: ((1, 2), 5)
2.3 实用方法
namedtuple是tuple的子类,具有tuple的所有方法
In [23]: p1 = Point(2,3)
In [24]: p2 = Point(3,4)
In [25]: p1+p2
Out[25]: (2, 3, 3, 4)
In [26]: p1.index(0)
In [27]: p1.index(2)
Out[27]: 0
In [29]: p1.count(1)
Out[29]: 0
In [30]: len(p1)
Out[30]: 2
namedtuple提供了其他方法让我么更灵活的使用该数据结构
In [46]: p._asdict()
Out[46]: OrderedDict([('x', 1), ('y', 2)])
In [47]: p._fields
Out[47]: ('x', 'y')
In [49]: p._make([1,2]) #传入可迭代类型
Out[49]: Ponit(x=1, y=2)
In [51]: p._replace(x=1,y=3) # 传入**kwds
Out[51]: Ponit(x=1, y=3)
3 OrderedDict
3.1 简介
python 中的dict是无序的,在对dict做迭代时我们无法确定dict的顺序。
OrderedDict是dict的子类,支持一般的dict方法,它会记录key加入的顺序,从而实现有序字典,这种数据结构具有强大的威力。
In [65]: d = dict([('a',1),('b',2),('c',3)])
In [66]: d
Out[66]: {'a': 1, 'b': 2, 'c': 3}
In [67]: od = OrderedDict([('a',1),('b',2),('c',3)])
In [68]: od
Out[68]: OrderedDict([('a', 1), ('b', 2), ('c', 3)])
In [70]: od = OrderedDict()
In [71]: od['z']=1
In [72]: od['x']=2
In [73]: od['y']=3
In [74]: od
Out[74]: OrderedDict([('z', 1), ('x', 2), ('y', 3)])
In [75]: for i in od:
...: print(i)
...:
z
x
y
OrderedDict会按照其插入的顺序给予键值对以固定的顺序,这样就可以得到“稳定”的迭代对象,并且可以取出固定位置的键值对
In [88]: od
Out[88]: OrderedDict([('z', 1), ('x', 2), ('y', 3)])
In [89]: od.get([x for x in od][2])
Out[89]: 3
3.2根据字典的键或值的特征进行排序
实现灵活排序
In [90]: d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}
In [91]: OrderedDict(sorted(d.items(), key=lambda t: t[0])) # 按照键排序
Out[91]: OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])
In [92]: OrderedDict(sorted(d.items(), key=lambda t: t[1])) # 按照值排序
Out[92]: OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])
In [93]: OrderedDict(sorted(d.items(), key=lambda t: len(t[0]))) # 按照键长度排序
Out[93]: OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])
# tips: sorted函数key变量,是指在对可迭代对象排序的时候,按照可迭代对象的什么特征进行排序
In [101]: a = ['5','40','345','6000']
In [102]: sorted(a #字符串第一个字符
Out[102]: ['345', '40', '5', '6000']
In [103]: sorted(a,key=lambda t:int(t)) #字符窜转化为int型之后
Out[103]: ['5', '40', '345', '6000']
这样就实现了对字典元素的顺序的定义
3.3 OrderedDict 相关方法
根据可迭代对象生成值为None 的有序字典
In [109]: d = OrderedDict.fromkeys('abcde')
In [110]: d
Out[110]: OrderedDict([('a', None), ('b', None), ('c', None), ('d', None), ('e', None)])
In [9]: d.move_to_end('b')
In [10]: d
Out[10]: OrderedDict([('a', None), ('c', None), ('d', None), ('e', None), ('b', None)])
In [11]: d.popitem()
Out[11]: ('b', None)
In [12]: d.popitem()
Out[12]: ('e', None)
In [13]: d
Out[13]: OrderedDict([('a', None), ('c', None), ('d', None)])
4 defaultdict
4.1 简介
默认值字典
python的dict数据类型在取值dict[key]的时候如果没有key会报错,defaultdict通过则避免了这一行为.使用defaultdict,只要你传入一个默认的工厂方法,那么请求一个不存在的key时, 便会调用这个工厂方法使用其结果来作为这个key的默认值。
其原理是在dict基础上实现了_missing_会调用传入的工厂方法 当_getitem_不存在的时候,就会触发,给本来不存在的键赋默认值
工厂方法默认为None,这个时候由于缺少工厂方法,对不存在的建设置默认值就不会生效
In [53]: d = defaultdict()
In [54]: d
Out[54]: defaultdict(None, {})
In [55]: d['a']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-55-4ff0d9af6f7a> in <module>()
----> 1 d['a']
KeyError: 'a'
当传入工厂方法的时候,设置默认值就会生效.
In [56]: d = defaultdict(list)
In [57]: d['a']
Out[57]: []
In [58]: d
Out[58]: defaultdict(list, {'a': []})
In [59]: d.get('a')
Out[59]: []
In [60]: d['a']
Out[60]: []
4.2 实现序列元素的收集
可以利用defaultdict实现序列元素的分类收集
In [34]: members = [
...: # Age, name
...: ['male', 'John'],
...: ['male', 'Jack'],
...: ['female', 'Lily'],
...: ['male', 'Pony'],
...: ['female', 'Lucy'],
...: ]
In [35]: result = defaultdict(list)
...: for sex, name in members:
...: result[sex].append(name)
...:
In [36]: result
Out[36]: defaultdict(list,{'female': ['Lily', 'Lucy'], 'male'['John', 'Jack', 'Pony']}
In [37]: result['male']
Out[37]: ['John', 'Jack', 'Pony']
当不存在key时候就会自动调用list工厂函数,产生一个空的列表,
上面的代码片段就实现了对具有相同信息的序列结构的筛选.使用dict可用如下方式实现.
In [39]: d = {}
In [40]: for sex, name in members:
...: d.setdefault(sex,[]).append(name)
...:
In [41]: d
Out[41]: {'female': ['Lily', 'Lucy'], 'male': ['John', 'Jack', 'Pony']}
带有默认值的字典
In [49]: f = lambda :'chaoge'
In [50]: d = defaultdict(f)
In [51]: d['a']
Out[51]: 'chaoge'
In [52]: d
Out[52]: defaultdict(<function __main__.<lambda>>, {'a': 'chaoge'})