Zodiac Wang
  • Home
  • Categories
  • Tags
  • Archives

collections模块小结

简单总结一下 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 字符串对象的包装器

Table of Contents

  • 1  namedtuple
  • 2  deque
  • 3  Counter
  • 4  OrderedDict
  • 5  defaultdict
  • 6  ChainMap
  • 7  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() 通过一个序列或可迭代对象创建
In [1]:
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
In [2]:
from collections import namedtuple

Point = namedtuple('Point', ['x', 'y', 'z'])
p = Point(10, 11, 12)
p
Out[2]:
Point(x=10, y=11, z=12)
In [3]:
Point(x=10, y=11, z=12)
p.x
p.x + p.y + p.z

p2 = Point(11, y=22, z=33)
p2

d = p2._asdict()      # 转换为字典
d

p2._replace(y=100)    # 替换元素值

p._fields             # 查看对象字段

Point._make(range(3)) # 通过一个序列或者可迭代对象创建一个对象
Out[3]:
Point(x=10, y=11, z=12)
Out[3]:
10
Out[3]:
33
Out[3]:
Point(x=11, y=22, z=33)
Out[3]:
OrderedDict([('x', 11), ('y', 22), ('z', 33)])
Out[3]:
Point(x=11, y=100, z=33)
Out[3]:
('x', 'y', 'z')
Out[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 内元素按顺序向后移动一位,最后一位移动到第一位
In [4]:
from collections import deque

dq = deque()
dq
Out[4]:
deque([])
In [5]:
dq.extend([1, 2, 3])
dq.extend([1, 2, 3])
dq
Out[5]:
deque([1, 2, 3, 1, 2, 3])
In [6]:
dq = deque(maxlen=2)
dq
Out[6]:
deque([])
In [7]:
dq.append(1)
dq.append(1)
dq
Out[7]:
deque([1, 1])
In [8]:
dq.append(3)
dq

dq.append(4)
dq

dq.appendleft(5)
dq
Out[8]:
deque([1, 3])
Out[8]:
deque([3, 4])
Out[8]:
deque([5, 3])

跑马灯程序

In [9]:
import sys
import time
from collections import deque

fancy_loading = deque('>--------------------')

cnt = 0
while cnt<20:
    print('\r%s' % ''.join(fancy_loading),)
    fancy_loading.rotate(1)
    sys.stdout.flush()
    time.sleep(0.05)
    cnt += 1
>--------------------
->-------------------
-->------------------
--->-----------------
---->----------------
----->---------------
------>--------------
------->-------------
-------->------------
--------->-----------
---------->----------
----------->---------
------------>--------
------------->-------
-------------->------
--------------->-----
---------------->----
----------------->---
------------------>--
------------------->-

Counter¶

Counter 用来统计相关元素的出现次数,返回一个 Counter 对象,类似于字典

collections.Counter([iterable-or-mapping])

常用方法

  • update 追加元素
  • most_common(n) 获取出现次数最多的 n 个元素
In [10]:
from collections import Counter

c = Counter('abracadabra')
c

c.update('zzzbbe')  # 追加元素
c

c.most_common(3)  # 获取出现频率最高的前 3 个字符
Out[10]:
Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
Out[10]:
Counter({'a': 5, 'b': 4, 'r': 2, 'c': 1, 'd': 1, 'z': 3, 'e': 1})
Out[10]:
[('a', 5), ('b', 4), ('z', 3)]

OrderedDict¶

OrderedDict 是 dict 的一个子类,支持所有 dict 的方法,保持 dict 的有序性

collections.OrderedDict([items])

常用方法

  • popitem(last = True)
  • move_to_end(key, last = True) 以上两个方法的 last 关键字参数都是控制从头还是尾弹出对象的
In [11]:
from collections import OrderedDict

d = OrderedDict({'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2})
d
Out[11]:
OrderedDict([('banana', 3), ('apple', 4), ('pear', 1), ('orange', 2)])
In [12]:
d['cherry'] = 8
d
Out[12]:
OrderedDict([('banana', 3),
             ('apple', 4),
             ('pear', 1),
             ('orange', 2),
             ('cherry', 8)])
In [13]:
for k, v in d.items():
    print(k, v)

d.keys()
banana 3
apple 4
pear 1
orange 2
cherry 8
Out[13]:
odict_keys(['banana', 'apple', 'pear', 'orange', 'cherry'])
In [14]:
d.pop('apple')
Out[14]:
4
In [15]:
d
Out[15]:
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[, …]])
In [16]:
from collections import defaultdict

d = defaultdict(lambda: None)
d
Out[16]:
defaultdict(<function __main__.<lambda>()>, {})
In [17]:
d['a']

print(d['b'])
None
In [18]:
d
Out[18]:
defaultdict(<function __main__.<lambda>()>, {'a': None, 'b': None})
In [19]:
d = defaultdict(int)
d["hello"]

d
Out[19]:
0
Out[19]:
defaultdict(int, {'hello': 0})

ChainMap¶

合成多个 dict 类似于 update 方法,只不过不是inplace实现,且效率更高

collections.ChainMap(*maps)
In [20]:
from collections import ChainMap

dict1 = { 'a' : 1, 'b' : 2 }
dict2 = { 'b' : 3, 'c' : 4 }
chain = ChainMap(dict1, dict2)
In [21]:
chain
Out[21]:
ChainMap({'a': 1, 'b': 2}, {'b': 3, 'c': 4})
In [22]:
chain.maps
Out[22]:
[{'a': 1, 'b': 2}, {'b': 3, 'c': 4}]
In [23]:
chain.keys()
Out[23]:
KeysView(ChainMap({'a': 1, 'b': 2}, {'b': 3, 'c': 4}))
In [24]:
list(chain.keys())
Out[24]:
['c', 'a', 'b']
In [25]:
chain['b']  # 获取的是第一个字典中的值

chain['a']

chain['c']
Out[25]:
2
Out[25]:
1
Out[25]:
4
In [26]:
chain['d'] = 5
chain['e'] = 6  # 被添加到了第一个字典中
chain
Out[26]:
ChainMap({'a': 1, 'b': 2, 'd': 5, 'e': 6}, {'b': 3, 'c': 4})
In [27]:
chain['b'] = 8  # 修改了第一个字典中的值
chain
Out[27]:
ChainMap({'a': 1, 'b': 8, 'd': 5, 'e': 6}, {'b': 3, 'c': 4})
In [28]:
m = chain.new_child()  # 复制一个 ChainMap 对象
m['g'] = 10
m
Out[28]:
ChainMap({'g': 10}, {'a': 1, 'b': 8, 'd': 5, 'e': 6}, {'b': 3, 'c': 4})
In [29]:
chain
Out[29]:
ChainMap({'a': 1, 'b': 8, 'd': 5, 'e': 6}, {'b': 3, 'c': 4})
In [30]:
dict3 = { 'h' : 5 }
new_chain = chain.new_child(dict3)  # 添加新字典
new_chain
Out[30]:
ChainMap({'h': 5}, {'a': 1, 'b': 8, 'd': 5, '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 模块中。这三个类都是基类,如果用户要扩展这三种类型,只需继承这三个类即可。

References:

  • Python 模块简介 collections

  • « PythonCookbook笔记(1)-数据结构和算法
  • 一道编程题 »

Published

10 3, 2018

Category

posts

Tags

  • collections 1
  • Python 16

Contact

  • Zodiac Wang - A Fantastic Learner
  • Powered by Pelican. Theme: Elegant