Python 标准库 collections¶
参考:
Python 的内置数据数据类型包括 str, int, list, tuple, set, dict 等,有时这些数据类型满足不了我们的需求。不过标准库的 collections 模块在这些内置数据类型的基础上,提供了几个额外的数据类型:
- namedtuple 命名元组,使用名字访问元素 New in version 2.6.
- deque 双端队列,可以快速的从头/尾两端添加或删除元素 New in version 2.4.
- Counter 计数器,用于对某项数据进行计数 New in version 2.7.
- OrderedDict 有序字典,保持插入顺序 New in version 2.7.
- defaultdict 带有默认值的字典 New in version 2.5.
- ChainMap 合并多个 map(dict),但保持原数据结构 New in version 3.3
- UserDict 将字典包装起来使得创建字典的子类更容易
- UserList 列表对象的包装器
- UserString 字符串对象的包装器
namedtuple¶
可以使用名称来访问元素的数据对象,返回一个 带 name fields 的子类
collections.namedtuple(typename, field_names, *, verbose=False, rename=False, module=None)
field_names 用于指定数据对象的元素,可以是一个 str,例如 'x y' 或者 'x, y',也可以是一个包含字符串的序列类型,像 ['x', 'y']
常用方法
- _asdict() 将 namedtuple 转换为一个 OrderedDict
- _fields() 返回 name fields 中的 key
- _replace() 类似于 str 的 replace 方法
- _make() 通过一个序列或可迭代对象创建
>>> Point = namedtuple('Point', ['x', 'y', 'z'])
>>> p = Point(10, 11, 12)
>>> p
Point(x=10, y=11, z=12)
>>> p.x
10
>>> p.x + p.y + p.z
33
>>> p2 = Point(11, y=22, z=33)
>>> p2
Point(x=11, y=22, z=33)
>>> d = p2._asdict() # 转换为字典
>>> d
OrderedDict([('x', 11), ('y', 22), ('z', 33)])
>>> p2._replace(y=100) # 替换元素值
Point(x=11, y=100, z=33)
>>> p._fields # 查看对象字段
('x', 'y', 'z')
>>> Point._make(range(3)) # 通过一个序列或者可迭代对象创建一个对象
Point(x=0, y=1, z=2
deque¶
deque 是 double-ended queue 的缩写,即双端队列。List 存储数据的优势在于按索引查找元素会很快,但是插入和删除元素就很慢了,因为 list 是基于数组实现的。deque 是为了高效实现插入和删除操作的双向列表,list存储数据的优势在于按索引查找元素会很快,但是插入和删除元素就很慢了,因为list是基于数组实现的。deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈,而且线程安全。
collections.deque([iterable[, maxlen]])
deque 具有 list 的所有方法,此外还有 appendleft/popleft ,插入元素的复杂度 O(1), 而 list 是 O(n)
maxlen 用于指定 deque 的最大长度,当 deque 的长度达到最大时,先加入的元素会按加入顺序被移出 deque ,如果不指定 maxlen 则为无限长。
常用方法
- append
- extend
- appendleft
- appendright
- popleft
- popright
- rotate deque 内元素按顺序移动一位,最后一位移动到第一位
>>> dq = deque()
>>> dq
deque([])
>>> dq.extend([1, 2, 3])
>>> dq.extend([1, 2, 3])
>>> dq
deque([1, 2, 3, 1, 2, 3])
>>> dq = deque(maxlen=2)
>>> dq
deque([], maxlen=2)
>>> dq.append(1)
>>> dq.append(1)
>>> dq
deque([1, 1], maxlen=2)
>>> dq.append(3)
>>> dq
deque([1, 3], maxlen=2)
>>> dq.append(4)
>>> dq
deque([3, 4], maxlen=2)
>>> dq.appendleft(5)
>>> dq
deque([5, 3], maxlen=2
跑马灯程序
import sys
import time
from collections import deque
fancy_loading = deque('>--------------------')
while True:
print('\r%s' % ''.join(fancy_loading),)
fancy_loading.rotate(1)
sys.stdout.flush()
time.sleep(0.08)
Counter¶
Counter 用来统计相关元素的出现次数,返回一个 Counter 对象,类似于字典
collections.Counter([iterable-or-mapping])
常用方法
- update 追加元素
- most_common(n) 获取出现次数最多的 n 个元素
>>> c = Counter('abracadabra')
>>> c
Counter({'a': 5, 'r': 2, 'b': 2, 'd': 1, 'c': 1})
>>> c.update('zzzbbe') # 追加元素
>>> c
Counter({'a': 5, 'b': 4, 'z': 3, 'r': 2, 'e': 1, 'c': 1, 'd': 1})
>>> c.most_common(3) # 获取出现频率最高的前 3 个字符
[('a', 5), ('b', 4), ('z', 3)]
OrderedDict¶
OrderedDict 是 dict 的一个子类,支持所有 dict 的方法,保持 dict 的有序性
collections.OrderedDict([items])
常用方法
- popitem(last = True)
- move_to_end(key, last = True) 以上两个方法的 last 关键字参数都是控制从头还是尾弹出对象的
>>> d = OrderedDict({'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2})
>>> d
OrderedDict([('banana', 3), ('apple', 4), ('pear', 1), ('orange', 2)])
>>> d['cherry'] = 8
>>> d
OrderedDict([('banana', 3), ('apple', 4), ('pear', 1), ('orange', 2), ('cherry', 8)])
>>> for k, v in d.items():
... print(k, v)
...
...
banana 3
apple 4
pear 1
orange 2
cherry 8
>>> d.keys()
odict_keys(['banana', 'apple', 'pear', 'orange', 'cherry'])
>>> d.pop('apple')
4
>>> d
OrderedDict([('banana', 3), ('pear', 1), ('orange', 2), ('cherry', 8)])
defaultdict¶
在普通的 dict 之上添加了 default_factory,使得 key 不存在时会自动生成相应类型的 value,default_factory 参数可以指定成 list, set, int 等各种合法类型
作用类似于 dict 中的 set_default 方法,代码更优雅一些
collections.defaultdict([default_factory[, …]])
>>> d = defaultdict(lambda: None)
>>> d
defaultdict(<function <lambda> at 0x1115ef620>, {})
>>> d['a']
>>> print(d['b'])
None
>>> d
defaultdict(<function <lambda> at 0x1115ef620>, {'a': None, 'b': None})
>>> d = defaultdict(int)
>>> d["hello"]
0
>>> d
defaultdict(<class 'int'>, {'hello': 0})
ChainMap¶
合成多个 dict 类似于 update 方法,只不过不是就地实现,且效率更高
collections.ChainMap(*maps)
>>> dict1 = { 'a' : 1, 'b' : 2 }
>>> dict2 = { 'b' : 3, 'c' : 4 }
>>> chain = ChainMap(dict1, dict2)
>>> chain
ChainMap({'a': 1, 'b': 2}, {'b': 3, 'c': 4})
>>> chain.maps
[{'a': 1, 'b': 2}, {'b': 3, 'c': 4}]
>>> chain.keys()
KeysView(ChainMap({'a': 1, 'b': 2}, {'b': 3, 'c': 4}))
>>> list(chain.keys())
['a', 'b', 'c']
>>> chain['b'] # 获取的是第一个字典中的值
2
>>> chain['a']
1
>>> chain['c']
4
>>> chain['d'] = 5
>>> chain['e'] = 6 # 被添加到了第一个字典中
>>> chain
ChainMap({'a': 1, 'd': 5, 'b': 2, 'e': 6}, {'b': 3, 'c': 4})
>>> chain['b'] = 8 # 修改了第一个字典中的值
>>> chain
ChainMap({'a': 1, 'd': 5, 'b': 8, 'e': 6}, {'b': 3, 'c': 4})
>>> m = chain.new_child() # 复制一个 ChainMap 对象
>>> m['g'] = 10
>>> m
ChainMap({'g': 10}, {'a': 1, 'd': 5, 'b': 8, 'e': 6}, {'b': 3, 'c': 4})
>>> chain
ChainMap({'a': 1, 'd': 5, 'b': 8, 'e': 6}, {'b': 3, 'c': 4})
>>> dict3 = { 'h' : 5 }
>>> new_chain = chain.new_child(dict3) # 添加新字典
>>> new_chain
ChainMap({'h': 5}, {'a': 1, 'd': 5, 'b': 8, 'e': 6}, {'b': 3, 'c': 4})
有时用 ChainMap 替代 update 是个不错的选择,但是 ChainMap 的绝大多数方法都只是在第一个字典上进行操作
UserDict UserList UserString¶
这三个类是分别对 dict、list、str 三种数据类型的包装,其主要是为方便用户实现自己的数据类型。在 Python2 之前,这三个类分别位于 UserDict、UserList、UserString 三个模块中,需要用类似于 from UserDict import UserDict 的方式导入。在 Python3 之后则被挪到了 collections 模块中。这三个类都是基类,如果用户要扩展这三种类型,只需继承这三个类即可。