collections --- 容器資料型別¶
原始碼:Lib/collections/__init__.py
這個模組實作了一些特別的容器資料型別,用來替代 Python 一般內建的容器,例如 dict(字典)、list(串列)、set(集合)和 tuple(元組)。
用來建立具名欄位的 tuple 子類別的工廠函式 |
|
一個類似 list 的容器,可以快速的在頭尾加入 (append) 元素與移除 (pop) 元素 |
|
一個類似 dict 的類別,用來為多個對映 (mapping) 建立單一的視圖 (view) |
|
dict 的子類別,用來計算可雜湊物件的數量 |
|
dict 的子類別,會記錄物件被加入的順序 |
|
dict 的子類別,當值不存在 dict 中時會呼叫一個提供預設值的工廠函式 |
|
dict 物件的包裝器 (wrapper),簡化了 dict 的子類別化過程 |
|
list 物件的包裝器,簡化了 list 的子類別化過程 |
|
字串物件的包裝器,簡化了字串的子類別化過程 |
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, 新對映後面接著目前實例的所有現存對映。如果有給定m,m會成為那個最前面的新對映;若沒有指定,則會加上一個空 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。
也參考
Enthought CodeTools package 中的 MultiContext class 支援在鏈中選定任意對映寫入。
Django 中用於模板的 Context class 是唯讀的對映鏈,也具有加入 (push) 和移除 (pop) 上下文的功能,與
new_child()方法和parents特性類似。Nested Contexts recipe 提供了控制是否只對鏈中第一個或其他對映做寫入或其他操作的選項。
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)]