写点什么

浅析 Python 中的 Collections 模块

作者:宇宙之一粟
  • 2022 年 2 月 02 日
  • 本文字数:2942 字

    阅读完需:约 10 分钟

浅析 Python 中的 Collections 模块

Collections 模块

本文将简单介绍一个 Python 模块 Collections 。这个模块实现了一些很好用的数据结构,可以帮助我们解决不同的实际问题。


import collections
复制代码

可以通过​​import collections​​​导入该模块的方法,现在我们进入 ipython3 然后使用​​dir(collections)​​查看 collections 下都有哪些可以用的类。

In [1]: import collections
In [2]: dir(collections)Out[2]:['ChainMap', 'Counter', 'OrderedDict', 'UserDict', 'UserList', 'UserString', '_Link', '_OrderedDictItemsView', '_OrderedDictKeysView', '_OrderedDictValuesView', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__getattr__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '_chain', '_collections_abc', '_count_elements', '_eq', '_heapq', '_iskeyword', '_itemgetter', '_nt_itemgetters', '_proxy', '_recursive_repr', '_repeat', '_starmap', '_sys', 'abc', 'defaultdict', 'deque', 'namedtuple']
复制代码


根据官方文档: 这个模块实现了特定目标的容器,以提供 Python 标准内建容器 ​​​dict​​​ , ​​​list​​​ , ​​​set​​​ , 和 ​​​tuple​​​ 的替代选择。



tuple 的功能


Counter

Counter 是一个 dict 子类,可帮助计算可哈希对象的值。在其中,元素存储为字典的键,值可以为零或负值。

在下例中,我们可以找到文件单词出现的次数:

from collections import Countersentence = "I can because i think i can"# Counter是一个简单的计数器,可以数组中统计字符出现的个数:counts = Counter(sentence.split())print(counts)  # Counter({'can': 2, 'i': 2, 'I': 1, 'because': 1, 'think': 1})
复制代码

Counter 对象有一个​​elements​​的方法,该方法在元素上返回迭代次数超过元素计数的迭代器。元素以任意顺序返回。

In [7]: c = Counter(a=4, b=2, c=0, d=-2)
In [8]: list(c.elements())Out[8]: ['a', 'a', 'a', 'a', 'b', 'b']
复制代码

​most_common​​是一种返回最常见元素及其计数(从最常见到最小)的方法。

In [9]: Counter('this is a test sentence').most_common(3)Out[9]: [('t', 4), ('s', 4), (' ', 4)]
复制代码

defaultdict

defaultdict 是类似于字典的对象,它提供字典提供的所有方法,但将第一个参数(default_factory)作为字典的默认数据类型。使用 defaultdict 比使用 dict.set_default 方法执行相同操作更快。

>>> from collections import defaultdict>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]>>> d = defaultdict(list)>>> for k, v in s:...     d[k].append(v)...>>> d.items()dict_items([('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])])
复制代码

在该示例中,即使 defaultdict 对象中没有键,您也可以看到它会自动创建一个空列表。list.append 然后有助于将值附加到列表中。

使用 dict 时,如果引用的 Key 不存在,就会抛出 KeyError。如果希望 key 不存在时,返回一个默认值,就可以用 defaultdict:

>>> from collections import defaultdict>>> dd = defaultdict(lambda: 'N/A')>>> dd['key1'] = 'abc'>>> dd['key1'] # key1存在'abc'>>> dd['key2'] # key2不存在,返回默认值'N/A'
复制代码

nametuple

命名元组有助于了解元组中每个位置的含义,并允许我们以更好的可读性和自记录代码进行编码。您可以在使用元组的任何地方使用它们。在示例中,我们将创建一个命名元组以显示点的保留信息。

>>> from collections import namedtuple>>> Point = namedtuple('Point', ['x', 'y'])  # Defining the namedtuple>>> p = Point(10, y=20)  # Creating an object>>> pPoint(x=10, y=20)>>> p.x + p.y30>>> p[0] + p[1]  # Accessing the values in normal way30>>> x, y = p     # Unpacking the tuple>>> x10>>> y20
复制代码

deque

deque 就是我们数据结构中听说的双端队列,Python 已经帮我实现了这个功能。

使用 list 存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为 list 是线性存储,数据量大的时候,插入和删除效率很低。

deque 是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:

>>> from collections import deque>>> q = deque(['a', 'b', 'c'])>>> q.append('x')>>> q.appendleft('y')>>> qdeque(['y', 'a', 'b', 'c', 'x'])
复制代码

deque 除了实现 list 的 append()和 pop()外,还支持 appendleft()和 popleft(),这样就可以非常高效地往头部添加或删除元素。

# -*- coding: utf-8 -*-"""下面这个是一个有趣的例子,主要使用了deque的rotate方法来实现了一个无限循环的加载动画"""import sysimport timefrom 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)
# Result:
# 一个无尽循环的跑马灯# ------------->-------
复制代码

OrderedDict

顾名思义,有序字典。当我们使用 dict 时,Key 是无序的。在对 dict 做迭代时,我们无法确定 Key 的顺序。

如果要保持 Key 的顺序,可以用 OrderedDict:

>>> from collections import OrderedDict>>> d = dict([('a', 1), ('b', 2), ('c', 3)])>>> d # dict的Key是无序的{'a': 1, 'c': 3, 'b': 2}>>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])>>> od # OrderedDict的Key是有序的OrderedDict([('a', 1), ('b', 2), ('c', 3)])
复制代码

注意,OrderedDict 的 Key 会按照插入的顺序排列,不是 Key 本身排序:

>>> od = OrderedDict()>>> od['z'] = 1>>> od['y'] = 2>>> od['x'] = 3>>> od.keys() # 按照插入的Key的顺序返回['z', 'y', 'x']
复制代码

ChainMap

3.3 新版功能.

一个 ​​​ChainMap​​​​ 类是为了将多个映射快速的链接到一起,这样它们就可以作为一个单元处理。它通常比创建一个新字典和多次调用 ​​​update()​​​ 要快很多。

ChainMap 可以把一组 dict 串起来并组成一个逻辑上的 dict。ChainMap 本身也是一个 dict,但是查找的时候,会按照顺序在内部的 dict 依次查找。

>>> baseline = {'music': 'bach', 'art': 'rembrandt'}>>> adjustments = {'art': 'van gogh', 'opera': 'carmen'}>>> list(ChainMap(adjustments, baseline))['music', 'art', 'opera']
复制代码

什么时候使用 ChainMap 最合适?举个例子:应用程序往往都需要传入参数,参数可以通过命令行传入,可以通过环境变量传入,还可以有默认参数。我们可以用 ChainMap 实现参数的优先级查找,即先查命令行参数,如果没有传入,再查环境变量,如果没有,就使用默认参数。

总结

  • Counter: 计数器,主要用来计数

  • defaultdict: 带有默认值的字典

  • namedtuple(): 生成可以使用名字来访问元素内容的 tuple 子类

  • deque: 双端队列,可以快速的从另外一侧追加和推出对象

  • OrderedDict: 有序字典

  • ChainMap:多个映射快速的链接到一起


站在巨人的肩膀上:

  1. 官方文档-- ​​​collections​​​ — 容器数据类型

  2. 免费视频课–​​​python必学模块-collections​​

  3. 廖大神的官方网站–​​​collections​​

  4. 不可不知的 Python 模块: ​​​collections​​

发布于: 刚刚阅读数: 2
用户头像

宇宙古今无有穷期,一生不过须臾,当思奋争 2020.05.07 加入

🏆InfoQ写作平台-第二季签约作者 🏆 混迹于江湖,江湖却没有我的影子 热爱技术,专注于后端全栈,轻易不换岗 拒绝内卷,工作于软件工程师,弹性不加班 热衷分享,执着于阅读写作,佛系不水文

评论

发布
暂无评论
浅析 Python 中的 Collections 模块