IT教程 ·

Python——详解collections工具库

进阶之路 | 奇妙的四大组件之旅

本文始发于个人民众号:TechFlow,原创不轻易,求个关注

 

本日为人人引见Python当中一个很好用也是很基本的东西库,叫做collections。

collection在英文当中有容器的意义,所以望文生义,这是一个容器的鸠合。这个库当中的容器很多,有一些不是很常常运用,本篇文章挑选了个中最常常运用的几个,一同引见给人人。

 

defaultdict

 

defaultdict能够说是这个库当中运用最简朴的一个,而且它的定义也很简朴,我们从称号基本上就能够看得出来。它处理的是我们运用dict当中最罕见的问题,就是key为空的状况。

在一般状况下,我们在dict中猎取元素的时刻,都须要斟酌key为空的状况。假如不斟酌这点,那末当我们猎取了一个不存在的key,会致使体系抛出异常。我们固然能够在每次get之前写一个if推断,然则这很贫苦,比方:

if key in dict:
    return dict[key]
else:
    return None

固然,这是最笨的要领,dict当中为我们供应了带默认值的get要领。比方,我们能够写成:

return dict.get(key, None)

如许,当key不在dict当中存在的时刻,会自动返回我们设置的默认值。这个省去了很多贫苦的推断,然则在一些特别状况下依然存在一点问题。举个例子,比方当key存在反复,我们愿望将key雷同的value存进一个list当中,而不是只保存一个。这类状况下写成代码就会比较复杂:

data = [(1, 3), (2, 1), (1, 4), (2, 5), (3, 7)]
d = {}
for k, v in data:
    if k in d:
        d[k].append(v)
    else:
        d[k] = [v]

由于dict的value是一个list,所以我们照样须要推断是不是为空,不能直接运用默认值,间接操纵固然能够,然则照样不够简朴:

for k, v in data:
    cur = d.get(k, [])
    cur.append(v)
    d[k] = v

这和运用if区分并不大,为了圆满处理这个问题,我们能够运用collections当中的defaultdict

from collections import defaultdict
d = defaultdict(list)

for k, v in data:
    d[k].append(v)

运用defaultdict以后,假如key不存在,容器会自动返回我们预先设置的默认值。须要注重的是defaultdict传入的默认值能够是一个范例也能够是一个要领。假如我们传入int,那末默认值会被设置成int()的效果,也就是0,假如我们想要自定义或许修正,我们能够传入一个要领,比方:

d = defaultdict(lambda: 3)

for k, v in data:
    d[k] += v

 

Counter

 

这是一个异常常常运用和异常壮大的东西,我们经常常运用到。

在我们现实的编程当中,我们常常碰到一个问题,就是数数和排序。比方说我们在剖析文本的时刻,会获得一堆单词。个中大概有大批的长尾词,在全部文本当中大概只涌现过寥寥频频。因而我们愿望盘算一下这些单词涌现过的数目,只保存涌现次数最高的若干个。

这个需求让我们本身完成固然也不难题,我们完全能够建立一个dict,然后对这些单词一个一个遍历。底本我们还须要斟酌单词之前没有涌现过的状况,假如我们上面说的defaultdict,又要简朴很多。然则我们照样少不了计数然后排序的步骤,假如运用Counter这个步骤会缩减成一行代码。

举个例子:

words = ['apple', 'apple', 'pear', 'watermelon', 'pear', 'peach']
from collections import Counter
counter = Counter(words)

>>> print(counter)

Counter({'apple': 2, 'pear': 2, 'watermelon': 1, 'peach': 1})

我们直接将一个list传入Counter中作为参数,它会自动为我们替当中的每一个元素计数。

假如我们要挑选topK,也异常简朴,它为我们供应了most_common要领,我们只须要传入须请求的K即可:

counter.most_common(1)

[('apple', 2)]

除此以外,它的组织函数还吸收dict范例。我们能够直接经由过程一个value是int范例的dict来初始化一个Counter,比方:

c = Counter({'apple': 5, 'pear': 4})
c = Counter(apple=4, pear=3)

而且,它还支撑加减法的操纵,比方我们能够将两个Counter相加,它会自动将两个Counter兼并,雷同的key对应的value累加。相减也是同理,会将能对应的value做减法,被减的key对应不上的会保存,而减数中对应不上的key则会被抛弃。而且须要注重,Counter支撑value为负数。

 

deque

 

我们都晓得queue是行列,deque也是行列,不过稍稍特别一些,是双端行列。关于queue来讲,只允许在队尾插进去元素,在队首弹出元素。而deque既然称为双端行列,那末申明它的队首和队尾都支撑元素的插进去和弹出。比拟于一般的行列,要越发天真一些。

除了常常运用的clear、copy、count、extend等api以外,deque当中最常常运用也是最中心的api另有append、pop、appendleft和popleft。从名字上我们就看得出来,append和pop和list的append和pop一样,而appendleft和popleft则是在行列左边,也就是头部举行pop和append的操纵。异常轻易明白。

在一样平常的运用当中,真正用到双端行列的算法实在不太多。大多数状况下我们运用deque主要有两个缘由,第一个缘由是deque收到GIL的治理,它是线程平安的。而list则没有GIL锁,因而不是线程平安的。也就是说在并发场景下,list大概会致使一致性问题,而deque不会。另一个缘由是deque支撑牢固长度,当长度满了以后,当我们继承append时,它会自动弹出最早插进去的数据。

比方说当我们具有海量的数据,我们不晓得它的数目,然则想要保存末了涌现的指定数目的数据的时刻,就能够够运用deque。

from collections import deque
dque = deque(maxlen=10)
# 假定我们想要从文件当中猎取末了10条数据
for i in f.read():
    dque.append(i)

 

namedtuple

 

namedtuple很特别,它涉及到元编程的观点。简朴引见一下元编程的观点,我们不做过量的深切。简而言之,就是在罕见的面向对象当中。我们都是定义类,然后经由过程类的组织函数来建立实例。而元编程指的是我们定义元类,依据元类建立出来的并非一个实例,而是一个类。假如用模具和制品来离别比方类和实例的话,元类相称因而模具的模具

namedtuple是一个异常简朴的元类,经由过程它我们能够异常方便地定义我们想要的类。

它的用法很简朴,我们直接来看例子。比方假如我们想要定义一个门生类,这个类当中有name、score、age这三个字段,那末这个类会写成:

class Student:
    def __init__(self, name=None, score=None, age=None):
        self.name = name
        self.score = score
        self.age = age

这还只是大略的写法,假如斟酌范例,还须要定义property等注解,又须要很多代码。假如我们运用namedtuple能够简化这个事情,我们来看代码:

from collections import namedtuple
# 这个是类,columns也能够写成'name score age',即用空格离开
Student = namedtuple('Student', ['name', 'score', 'age'])

# 这个是实例
student = Student(name='xiaoming', score=99, age=10)
print(student.name)

经由过程运用namedtuple,我们只须要一行就定义了一个类,然则如许定义的类是没有缺失值的,然则namedtuple很壮大,我们能够经由过程传入defaults参数来定义缺失值。

Student = namedtuple('Student', ['name', 'score', 'age'], defaults=(0, 0))

能够注重到,虽然我们定义了三个字段,然则我们只设置了两个缺失值。在这类状况下,namedtuple会自动将缺失值匹配上score和age两个字段。由于在Python的范例当中,必选参数一定在可选参数前面。所以nuamdtuple会自动右对齐。

细数一下,我们本日的文章当中引见了defaultdict、Counter、deque和namedtuple这四种数据结构的用法。除了这四个以外,collections库当中另有一些其他的东西类,只是我们用的频次稍稍低一些,加上由于篇幅的缘由,这里就不多做赘述了。感兴趣的同砚能够自行检察相干的api和文档。

本日的文章就是这些,假如以为有所收成,请随手扫码点个关注吧,你们的举手之劳对我来讲很主要。

一起了解 .Net Foundation 项目 No.10

参与评论