<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Python進(jìn)階 | 詳解collections工具庫(kù),一篇文章全搞定!

          共 4084字,需瀏覽 9分鐘

           ·

          2020-09-06 09:16

          前言

          大家好,今天為大家介紹Python當(dāng)中一個(gè)很好用也是很基礎(chǔ)的工具庫(kù),叫做collections

          collection在英文當(dāng)中有容器的意思,所以顧名思義,這是一個(gè)容器的集合。這個(gè)庫(kù)當(dāng)中的容器很多,有一些不是很常用,本篇文章選擇了其中最常用的幾個(gè),一起介紹給大家。

          defaultdict

          defaultdict可以說(shuō)是這個(gè)庫(kù)當(dāng)中使用最簡(jiǎn)單的一個(gè),并且它的定義也很簡(jiǎn)單,我們從名稱基本上就能看得出來(lái)。它解決的是我們使用dict當(dāng)中最常見的問題,就是key為空的情況。

          在正常情況下,我們?cè)赿ict中獲取元素的時(shí)候,都需要考慮key為空的情況。如果不考慮這點(diǎn),那么當(dāng)我們獲取了一個(gè)不存在的key,會(huì)導(dǎo)致系統(tǒng)拋出異常。我們當(dāng)然可以在每次get之前寫一個(gè)if判斷,但是這很麻煩,比如:

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

          當(dāng)然,這是最笨的方法,dict當(dāng)中為我們提供了帶默認(rèn)值的get方法。比如,我們可以寫成:

          return?dict.get(key,?None)

          這樣,當(dāng)key不在dict當(dāng)中存在的時(shí)候,會(huì)自動(dòng)返回我們?cè)O(shè)置的默認(rèn)值。這個(gè)省去了很多麻煩的判斷,但是在一些特殊情況下仍然存在一點(diǎn)問題。舉個(gè)例子,比如當(dāng)key存在重復(fù),我們希望將key相同的value存進(jìn)一個(gè)list當(dāng)中,而不是只保留一個(gè)。這種情況下寫成代碼就會(huì)比較復(fù)雜:

          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是一個(gè)list,所以我們還是需要判斷是否為空,不能直接使用默認(rèn)值,間接操作當(dāng)然可以,但是還是不夠簡(jiǎn)單:

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

          這和使用if區(qū)別并不大,為了完美解決這個(gè)問題,我們可以使用collections當(dāng)中的defaultdict

          from?collections?import?defaultdict
          d?=?defaultdict(list)

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

          使用defaultdict之后,如果key不存在,容器會(huì)自動(dòng)返回我們預(yù)先設(shè)置的默認(rèn)值。需要注意的是defaultdict傳入的默認(rèn)值可以是一個(gè)類型也可以是一個(gè)方法。如果我們傳入int,那么默認(rèn)值會(huì)被設(shè)置成int()的結(jié)果,也就是0,如果我們想要自定義或者修改,我們可以傳入一個(gè)方法,比如:

          d?=?defaultdict(lambda:?3)

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

          Counter

          這是一個(gè)非常常用和非常強(qiáng)大的工具,我們經(jīng)常用到。

          在我們實(shí)際的編程當(dāng)中,我們經(jīng)常遇到一個(gè)問題,就是數(shù)數(shù)和排序。比如說(shuō)我們?cè)诜治鑫谋镜臅r(shí)候,會(huì)得到一堆單詞。其中可能有大量的長(zhǎng)尾詞,在整個(gè)文本當(dāng)中可能只出現(xiàn)過(guò)寥寥幾次。于是我們希望計(jì)算一下這些單詞出現(xiàn)過(guò)的數(shù)量,只保留出現(xiàn)次數(shù)最高的若干個(gè)。

          這個(gè)需求讓我們自己實(shí)現(xiàn)當(dāng)然也不困難,我們完全可以創(chuàng)建一個(gè)dict,然后對(duì)這些單詞一個(gè)一個(gè)遍歷。原本我們還需要考慮單詞之前沒有出現(xiàn)過(guò)的情況,如果我們上面說(shuō)的defaultdict,又要簡(jiǎn)單許多。但是我們還是少不了計(jì)數(shù)然后排序的步驟,如果使用Counter這個(gè)步驟會(huì)縮減成一行代碼。

          舉個(gè)例子:

          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})

          我們直接將一個(gè)list傳入Counter中作為參數(shù),它會(huì)自動(dòng)為我們替當(dāng)中的每個(gè)元素計(jì)數(shù)。

          如果我們要篩選topK,也非常簡(jiǎn)單,它為我們提供了most_common方法,我們只需要傳入需要求的K即可:

          counter.most_common(1)

          [('apple',?2)]

          除此之外,它的構(gòu)造函數(shù)還接收dict類型。我們可以直接通過(guò)一個(gè)value是int類型的dict來(lái)初始化一個(gè)Counter,比如:

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

          并且,它還支持加減法的操作,比如我們可以將兩個(gè)Counter相加,它會(huì)自動(dòng)將兩個(gè)Counter合并,相同的key對(duì)應(yīng)的value累加。相減也是同理,會(huì)將能對(duì)應(yīng)的value做減法,被減的key對(duì)應(yīng)不上的會(huì)保留,而減數(shù)中對(duì)應(yīng)不上的key則會(huì)被丟棄。并且需要注意,Counter支持value為負(fù)數(shù)。

          deque

          我們都知道queue是隊(duì)列,deque也是隊(duì)列,不過(guò)稍稍特殊一些,是雙端隊(duì)列。對(duì)于queue來(lái)說(shuō),只允許在隊(duì)尾插入元素,在隊(duì)首彈出元素。而deque既然稱為雙端隊(duì)列,那么說(shuō)明它的隊(duì)首和隊(duì)尾都支持元素的插入和彈出。相比于普通的隊(duì)列,要更加靈活一些。

          除了常用的clear、copy、count、extend等api之外,deque當(dāng)中最常用也是最核心的api還有append、pop、appendleft和popleft。從名字上我們就看得出來(lái),append和pop和list的append和pop一樣,而appendleft和popleft則是在隊(duì)列左側(cè),也就是頭部進(jìn)行pop和append的操作。非常容易理解。

          在日常的使用當(dāng)中,真正用到雙端隊(duì)列的算法其實(shí)不太多。大多數(shù)情況下我們使用deque主要有兩個(gè)原因,第一個(gè)原因是deque收到GIL的管理,它是線程安全的。而list則沒有GIL鎖,因此不是線程安全的。也就是說(shuō)在并發(fā)場(chǎng)景下,list可能會(huì)導(dǎo)致一致性問題,而deque不會(huì)。另一個(gè)原因是deque支持固定長(zhǎng)度,當(dāng)長(zhǎng)度滿了之后,當(dāng)我們繼續(xù)append時(shí),它會(huì)自動(dòng)彈出最早插入的數(shù)據(jù)。

          比如說(shuō)當(dāng)我們擁有海量的數(shù)據(jù),我們不知道它的數(shù)量,但是想要保留最后出現(xiàn)的指定數(shù)量的數(shù)據(jù)的時(shí)候,就可以使用deque。

          from?collections?import?deque
          dque?=?deque(maxlen=10)
          #?假設(shè)我們想要從文件當(dāng)中獲取最后10條數(shù)據(jù)
          for?i?in?f.read():
          ????dque.append(i)

          namedtuple

          namedtuple很特殊,它涉及到元編程的概念。簡(jiǎn)單介紹一下元編程的概念,我們不做過(guò)多的深入。簡(jiǎn)而言之,就是在常見的面向?qū)ο螽?dāng)中。我們都是定義類,然后通過(guò)類的構(gòu)造函數(shù)來(lái)創(chuàng)建實(shí)例。而元編程指的是我們定義元類,根據(jù)元類創(chuàng)建出來(lái)的并不是一個(gè)實(shí)例,而是一個(gè)類。如果用模具和成品來(lái)分別比喻類和實(shí)例的話,元類相當(dāng)于是模具的模具。

          namedtuple是一個(gè)非常簡(jiǎn)單的元類,通過(guò)它我們可以非常方便地定義我們想要的類。

          它的用法很簡(jiǎn)單,我們直接來(lái)看例子。比如如果我們想要定義一個(gè)學(xué)生類,這個(gè)類當(dāng)中有name、score、age這三個(gè)字段,那么這個(gè)類會(huì)寫成:

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

          這還只是粗略的寫法,如果考慮規(guī)范,還需要定義property等注解,又需要很多代碼。如果我們使用namedtuple可以簡(jiǎn)化這個(gè)工作,我們來(lái)看代碼:

          from?collections?import?namedtuple
          #?這個(gè)是類,columns也可以寫成'name?score?age',即用空格分開
          Student?=?namedtuple('Student',?['name',?'score',?'age'])

          #?這個(gè)是實(shí)例
          student?=?Student(name='xiaoming',?score=99,?age=10)
          print(student.name)

          通過(guò)使用namedtuple,我們只需要一行就定義了一個(gè)類,但是這樣定義的類是沒有缺失值的,但是namedtuple很強(qiáng)大,我們可以通過(guò)傳入defaults參數(shù)來(lái)定義缺失值。

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

          可以注意到,雖然我們定義了三個(gè)字段,但是我們只設(shè)置了兩個(gè)缺失值。在這種情況下,namedtuple會(huì)自動(dòng)將缺失值匹配上score和age兩個(gè)字段。因?yàn)樵赑ython的規(guī)范當(dāng)中,必選參數(shù)一定在可選參數(shù)前面。所以nuamdtuple會(huì)自動(dòng)右對(duì)齊。

          細(xì)數(shù)一下,我們今天的文章當(dāng)中介紹了defaultdict、Counterdequenamedtuple這四種數(shù)據(jù)結(jié)構(gòu)的用法。除了這四個(gè)之外,collections庫(kù)當(dāng)中還有一些其他的工具類,只是我們用的頻率稍稍低一些,加上由于篇幅的原因,這里就不多做贅述了。感興趣的同學(xué)可以自行查看相關(guān)的api和文檔。

          今天的文章就是這些,如果覺得有所收獲,請(qǐng)順手來(lái)個(gè)三連(點(diǎn)贊、在看、留言)吧!

          -END-



          瀏覽 52
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕在线观看的视频 | 婷婷五月天最新网址 | 少妇日批 | 日韩免费黄色电影网站 | 艹逼电影 |