不可不知的python模組–collections

君惜發表於2019-02-16

基本介紹

Python擁有一些內建的資料型別,比如str, int, list, tuple, dict等, collections模組在這些內建資料型別的基礎上,提供了幾個額外的資料型別:

  • namedtuple(): 生成可以使用名字來訪問元素內容的tuple子類
  • deque: 雙端佇列,可以快速的從另外一側追加和推出物件
  • Counter: 計數器,主要用來計數
  • OrderedDict: 有序字典
  • defaultdict: 帶有預設值的字典

namedtuple()

namedtuple主要用來產生可以使用名稱來訪問元素的資料物件,通常用來增強程式碼的可讀性, 在訪問一些tuple型別的資料時尤其好用。
例子1:

import collections

coordinate = collections.namedtuple(`Coordinate`, [`x`, `y`])
co = coordinate(10,20)
print(type(co))
print(co)
print(co.x, co.y)
print(co[0], co[1])
co = coordinate._make([100, 200])
print(co)
print(co.x, co.y)
co = co._replace(x=30)
print(co)
print(co.x, co.y)

執行:

<class `__main__.Coordinate`>
Coordinate(x=10, y=20)
10 20
10 20
Coordinate(x=100, y=200)
100 200
Coordinate(x=30, y=200)
30 200

例子2:

websites = [
    (`Sohu`, `http://www.sohu.com/`, u`張朝陽`),
    (`Sina`, `http://www.sina.com.cn/`, u`王志東`),
    (`163`, `http://www.163.com/`, u`丁磊`)
]

Website = collections.namedtuple(`Website`, [`name`, `url`, `founder`])

for website in websites:
    website = Website._make(website)
    print(website)

執行:

Website(name=`Sohu`, url=`http://www.sohu.com/`, founder=`張朝陽`)
Website(name=`Sina`, url=`http://www.sina.com.cn/`, founder=`王志東`)
Website(name=`163`, url=`http://www.163.com/`, founder=`丁磊`)

例子3(一摞有序的紙牌):

import collections
Card = collections.namedtuple(`Card`, [`rank`, `suit`])


class FrenchDeck:
    ranks = [str(n) for n in range(2, 11)] + list(`JQKA`)
    suits = `spades diamonds clubs hearts`.split()

    def __init__(self):
        self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks]

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, position):
        return self._cards[position]

beer_card = Card(`7`, `diamonds`)
print(beer_card)

deck = FrenchDeck()
print(len(deck))

print(deck._cards)
print(deck[0])
print(deck[-1])

from random import choice
print(choice(deck))

print(deck[:3])
print(deck[12::13])     # 先抽出索引是 12 的那張牌,然後每隔 13 張牌拿 1 張

for card in deck:
    print(card)

for card in reversed(deck):
    print(card)

deque

deque其實是 double-ended queue 的縮寫,翻譯過來就是雙端佇列,它最大的好處就是實現了從佇列 頭部快速增加和取出物件: .popleft(), .appendleft() 。

原生的list也可以從頭部新增和取出物件?就像這樣:

l.insert(0, v)
l.pop(0)

但是值得注意的是,list物件的這兩種用法的時間複雜度是 O(n) ,也就是說隨著元素數量的增加耗時呈 線性上升。而使用deque物件則是 O(1) 的複雜度,所以當你的程式碼有這樣的需求的時候, 一定要記得使用deque。

作為一個雙端佇列,deque還提供了一些其他的好用方法,比如 rotate 等。

例子:

# -*- coding: utf-8 -*-
"""
下面這個是一個有趣的例子,主要使用了deque的rotate方法來實現了一個無限迴圈
的載入動畫
"""
import sys
import time
from collections import deque

fancy_loading = deque(`>--------------------`)

while True:
    print `
%s` % ``.join(fancy_loading),
    fancy_loading.rotate(1)
    sys.stdout.flush()
    time.sleep(0.08)

執行:

# 一個無盡迴圈的跑馬燈
------------->-------

Counter

計數器是一個非常常用的功能需求,collections也貼心的為你提供了這個功能。

例子:

# -*- coding: utf-8 -*-
"""
下面這個例子就是使用Counter模組統計一段句子裡面所有字元出現次數
"""
from collections import Counter

s = ```A Counter is a dict subclass for counting hashable objects. It is an unordered collection where elements are stored as dictionary keys and their counts are stored as dictionary values. Counts are allowed to be any integer value including zero or negative counts. The Counter class is similar to bags or multisets in other languages.```.lower()

c = Counter(s)
# 獲取出現頻率最高的5個字元
print c.most_common(5)

執行:

[(` `, 54), (`e`, 32), (`s`, 25), (`a`, 24), (`t`, 24)]

OrderedDict

在Python中,dict這個資料結構由於hash的特性,是無序的,這在有的時候會給我們帶來一些麻煩, 幸運的是,collections模組為我們提供了OrderedDict,當你要獲得一個有序的字典物件時,用它就對了。

例子:

# -*- coding: utf-8 -*-
from collections import OrderedDict

items = (
    (`A`, 1),
    (`B`, 2),
    (`C`, 3)
)

regular_dict = dict(items)
ordered_dict = OrderedDict(items)

print `Regular Dict:`
for k, v in regular_dict.items():
    print k, v

print `Ordered Dict:`
for k, v in ordered_dict.items():
    print k, v

執行:

Regular Dict:
A 1
C 3
B 2
Ordered Dict:
A 1
B 2
C 3

defaultdict

我們都知道,在使用Python原生的資料結構dict的時候,如果用 d[key] 這樣的方式訪問, 當指定的key不存在時,是會丟擲KeyError異常的。

但是,如果使用defaultdict,只要你傳入一個預設的工廠方法,那麼請求一個不存在的key時, 便會呼叫這個工廠方法使用其結果來作為這個key的預設值。

# -*- coding: utf-8 -*-
from collections import defaultdict

members = [
    # Age, name
    [`male`, `John`],
    [`male`, `Jack`],
    [`female`, `Lily`],
    [`male`, `Pony`],
    [`female`, `Lucy`],
]

result = defaultdict(list)
for sex, name in members:
    result[sex].append(name)

print result

執行:

defaultdict(<type `list`>, {`male`: [`John`, `Jack`, `Pony`], `female`: [`Lily`, `Lucy`]})

相關文章