python collections模块
collections模块
在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。
1.namedtuple: 生成可以使用名字来访问元素内容的tuple
2.deque: 双端队列,可以快速的从另外一侧追加和推出对象
3.Counter: 计数器,主要用来计数
4.OrderedDict: 有序字典
5.defaultdict: 带有默认值的字典
namedtuple(具名元组)
因为元组的局限性:不能为元组内部的数据进行命名,所以往往我们并不知道一个元组所要表达的意义,所以在这里引入了 collections.namedtuple 这个工厂函数,来构造一个带字段名的元组。具名元组的实例和普通元组消耗的内存一样多,因为字段名都被存在对应的类里面。这个类跟普通的对象实例比起来也要小一些,因为 Python 不会用 __dict__ 来存放这些实例的属性。
namedtuple 对象的定义如以下格式:
collections.namedtuple(typename, field_names, verbose=False, rename=False)
返回一个具名元组子类 typename,其中参数的意义如下:
- typename:元组名称
- field_names: 元组中元素的名称
- rename: 如果元素名称中含有 python 的关键字,则必须设置为 rename=True
- verbose: 默认就好
下面来看看声明一个具名元组及其实例化的方法:
from collections import namedtuple # 两种方法来给 namedtuple 定义方法名 #User = namedtuple('User', ['name', 'age', 'id']) User = namedtuple('User', 'name age id') user = User('tester', '22', '464643123') print(user) #输出结果 User(name='tester', age='22', id='464643123')
collections.namedtuple('User', 'name age id') 创建一个具名元组,需要两个参数,一个是类名,另一个是类的各个字段名。后者可以是有多个字符串组成的可迭代对象,或者是有空格分隔开的字段名组成的字符串(比如本示例)。具名元组可以通过字段名或者位置来获取一个字段的信息。
具名元组的特有属性:
- 类属性 _fields:包含这个类所有字段名的元组
- 类方法 _make(iterable):接受一个可迭代对象来生产这个类的实例
- 实例方法 _asdict():把具名元组以 collections.OrdereDict 的形式返回,可以利用它来把元组里的信息友好的展示出来
from collections import namedtuple # 定义一个namedtuple类型User,并包含name,sex和age属性。 User = namedtuple('User', ['name', 'sex', 'age']) # 创建一个User对象 user = User(name='Runoob', sex='male', age=12) # 获取所有字段名 print( user._fields ) # 也可以通过一个list来创建一个User对象,这里注意需要使用"_make"方法 user = User._make(['Runoob', 'male', 12]) print( user ) # User(name='user1', sex='male', age=12) # 获取用户的属性 print( user.name ) print( user.sex ) print( user.age ) # 修改对象属性,注意要使用"_replace"方法 user = user._replace(age=22) print( user ) # User(name='user1', sex='male', age=21) # 将User对象转换成字典,注意要使用"_asdict" print( user._asdict() ) # OrderedDict([('name', 'Runoob'), ('sex', 'male'), ('age', 22)]) #以上实例输出结果为: ('name', 'sex', 'age') User(name='Runoob', sex='male', age=12) Runoob male 12 User(name='Runoob', sex='male', age=22) OrderedDict([('name', 'Runoob'), ('sex', 'male'), ('age', 22)])
deque(双向列表)
使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。
deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:
1.创建deque序列: from collections import deque d=deque() 2.deque提供了类似list的操作方法: d=deque() d.append(3) d.append(8) d.append(1) 那么此时d=deque([3,8,1]),len(d)=3,d[0]=3,d[-1]=1 3.两端都使用pop: d=deque(‘12345’) 那么d=deque(['1', '2', '3', '4', '5']) d.pop()抛出的是’5’,d.leftpop()抛出的是’1’,可见默认pop()抛出的是最后一个元素。 #4.限制deque的长度 d=deque(maxlen=20) for i in range(30): d.append(str(i)) #此时d的值为d=deque(['10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29'], maxlen=20),可见当限制长度的deque增加超过限制数的项时,另一边的项会自动删除。 #5.添加list各项到deque中: d=deque([1,2,3,4,5]) d.extend([0]) #那么此时d=deque([1,2,3,4,5,0]) d.extendleft([6,7,8]) #此时d=deque([8, 7, 6, 1, 2, 3, 4, 5, 0])
OrderedDict(有序字典)
使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。
如果要保持Key的顺序,可以用OrderedDict
:
from collections import OrderedDict d = dict([('a', 1), ('b', 2), ('c', 3)]) print(d) # dict的Key是无序的 #输出 {'a': 1, 'c': 3, 'b': 2} od = OrderedDict([('a', 1), ('b', 2), ('c', 3)]) print(od) # OrderedDict的Key是有序的 #输出 OrderedDict([('a', 1), ('b', 2), ('c', 3)])
注意,OrderedDict
的Key会按照插入的顺序排列,不是Key本身排序:
od = OrderedDict() od['z'] = 1 od['y'] = 2 od['x'] = 3 print(od.keys()) # 按照插入的Key的顺序返回 #['z', 'y', 'x']
defaultdict (默认字典)
bag = ['apple', 'orange', 'cherry', 'apple','apple', 'cherry', 'blueberry'] count = {} for fruit in bag: count[fruit] += 1 错误: KeyError: 'apple'
defaultdict类避免KeyError异常:
import collections bag = ['apple', 'orange', 'cherry', 'apple','apple', 'cherry', 'blueberry'] count = collections.defaultdict(int) for fruit in bag: count[fruit] += 1 输出: defaultdict(<class 'int'>, {'apple': 3, 'orange': 1, 'cherry': 2, 'blueberry': 1})
如何使用defaultdict
defaultdict接受一个工厂函数作为参数,如下来构造:
dict =defaultdict( factory_function)
这个factory_function可以是list、set、str等等,作用是当key不存在时,返回的是工厂函数的默认值,比如list对应[ ],str对应的是空字符串,set对应set( ),int对应0
from collections import defaultdict def zero(): return 0 dic = defaultdict(zero) dic['bbb'] print(dic) #输出: #defaultdict(<function zero at 0x000001754EB4B488>, {'bbb': 0})
Counter(计数器)
Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。Counter类和其他语言的bags或multisets很相似。
c = Counter('abcdeabcdabcaba') print c 输出:Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})