collections --- 容器資料型別

原始碼:Lib/collections/__init__.py


這個模組實作了一些特別的容器資料型別,用來替代 Python 一般內建的容器,例如 dict(字典)、list(串列)、set(集合)和 tuple(元組)。

namedtuple()

用來建立具名欄位的 tuple 子類別的工廠函式

deque

一個類似 list 的容器,可以快速的在頭尾加入 (append) 元素與移除 (pop) 元素

ChainMap

一個類似 dict 的類別,用來為多個對映 (mapping) 建立單一的視圖 (view)

Counter

dict 的子類別,用來計算可雜湊物件的數量

OrderedDict

dict 的子類別,會記錄物件被加入的順序

defaultdict

dict 的子類別,當值不存在 dict 中時會呼叫一個提供預設值的工廠函式

UserDict

dict 物件的包裝器 (wrapper),簡化了 dict 的子類別化過程

UserList

list 物件的包裝器,簡化了 list 的子類別化過程

UserString

字串物件的包裝器,簡化了字串的子類別化過程

ChainMap 物件

在 3.3 版被加入.

ChainMap(對映鏈結)類別的目的是快速將數個對映連結在一起,讓它們可以被當作一個單元來處理。它通常會比建立一個新的字典並多次呼叫 update() 來得更快。

這個類別可用於模擬巢狀作用域 (nested scopes),且在模板化 (templating) 時能派上用場。

class collections.ChainMap(*maps)

一個 ChainMap 將多個 dict 或其他對映組合在一起,建立一個獨立、可更新的視圖。如果沒有指定 maps,預設會提供一個空字典讓每個新鏈結都至少有一個對映。

底層的對映儲存於一個 list 中,這個 list 是公開的且可透過 maps 屬性存取或更新,沒有其他狀態 (state)。

檢索 (lookup) 陸續查詢底層對映,直到鍵被找到,然而讀取、更新和刪除就只會對第一個對映操作。

ChainMap 透過參照將底層對映合併,所以當一個底層對映被更新,這些改變也會反映到 ChainMap

所有常見的字典方法都有支援。此外,還有一個 maps 屬性 (attribute)、一個建立子上下文 (subcontext) 的方法、和一個能夠存取除了第一個以外其他所有對映的特性 (property):

maps

一個可被更新的對映列表,這個列表是按照被搜尋的順序來排列,在 ChainMap 中它是唯一被儲存的狀態,可被修改來變換搜尋順序。回傳的列表都至少包含一個對映。

new_child(m=None, **kwargs)

回傳包含一個新對映的 ChainMap, 新對映後面接著目前實例的所有現存對映。如果有給定 mm 會成為那個最前面的新對映;若沒有指定,則會加上一個空 dict,如此一來呼叫 d.new_child() 就等同於 ChainMap({}, *d.maps)。這個方法用於建立子上下文,而保持父對映的不變。

在 3.4 版的變更: 加入可選參數 m

在 3.10 版的變更: 增加了對關鍵字引數的支援。

parents

回傳一個包含除了第一個以外所有其他對映的新 ChainMap 的特性,可用於需要跳過第一個對映的搜尋。使用情境類似於在巢狀作用域當中使用 nonlocal 關鍵字,也可與內建函式 super() 做類比。引用 d.parents 等同於 ChainMap(*d.maps[1:])

注意,一個 ChainMap 的疊代順序是透過由後往前掃描對映而定:

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

這和呼叫 dict.update() 結果的順序一樣是從最後一個對映開始:

>>> combined = baseline.copy()
>>> combined.update(adjustments)
>>> list(combined)
['music', 'art', 'opera']

在 3.9 版的變更: 支援 ||= 運算子,詳見 PEP 584

也參考

ChainMap 範例和用法

此章節提供了多種操作 ChainMap 的案例。

模擬 Python 內部檢索鏈結的例子:

import builtins
pylookup = ChainMap(locals(), globals(), vars(builtins))

讓使用者指定的命令列引數優先於環境變數、再優先於預設值的範例:

import os, argparse

defaults = {'color': 'red', 'user': 'guest'}

parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args()
command_line_args = {k: v for k, v in vars(namespace).items() if v is not None}

combined = ChainMap(command_line_args, os.environ, defaults)
print(combined['color'])
print(combined['user'])

ChainMap 類別模擬巢狀上下文的範例模式:

c = ChainMap()        # Create root context
d = c.new_child()     # Create nested child context
e = c.new_child()     # Child of c, independent from d
e.maps[0]             # Current context dictionary -- like Python's locals()
e.maps[-1]            # Root context -- like Python's globals()
e.parents             # Enclosing context chain -- like Python's nonlocals

d['x'] = 1            # Set value in current context
d['x']                # Get first key in the chain of contexts
del d['x']            # Delete from current context
list(d)               # All nested values
k in d                # Check all nested values
len(d)                # Number of nested values
d.items()             # All nested items
dict(d)               # Flatten into a regular dictionary

ChainMap 類別只對鏈結中第一個對映來做寫入或刪除,但檢索則會掃過整個鏈結。但如果需要對更深層的鍵寫入或刪除,透過定義一個子類別來實作也不困難:

class DeepChainMap(ChainMap):
    'Variant of ChainMap that allows direct updates to inner scopes'

    def __setitem__(self, key, value):
        for mapping in self.maps:
            if key in mapping:
                mapping[key] = value
                return
        self.maps[0][key] = value

    def __delitem__(self, key):
        for mapping in self.maps:
            if key in mapping:
                del mapping[key]
                return
        raise KeyError(key)

>>> d = DeepChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'})
>>> d['lion'] = 'orange'         # update an existing key two levels down
>>> d['snake'] = 'red'           # new keys get added to the topmost dict
>>> del d['elephant']            # remove an existing key one level down
>>> d                            # display result
DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})

Counter 物件

提供一個支援方便且快速計數的計數器工具,例如:

>>> # Tally occurrences of words in a list
>>> cnt = Counter()
>>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
...     cnt[word] += 1
...
>>> cnt
Counter({'blue': 3, 'red': 2, 'green': 1})

>>> # Find the ten most common words in Hamlet
>>> import re
>>> words = re.findall(r'\w+', open('hamlet.txt').read().lower())
>>> Counter(words).most_common(10)
[('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631),
 ('you', 554),  ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)]
class collections.Counter(**kwargs)
class collections.Counter(iterable, /, **kwargs)
class collections.Counter(mapping, /, **kwargs)

Counterdict 的子類別,用來計算可雜湊物件的數量。它是將物件與其計數作為字典的鍵值對儲存的集合容器。計數可以是包含 0 與負數的任何整數值。