collections
--- 容器數(shù)據(jù)類(lèi)型?
Source code: Lib/collections/__init__.py
這個(gè)模塊實(shí)現(xiàn)了特定目標(biāo)的容器,以提供Python標(biāo)準(zhǔn)內(nèi)建容器 dict
, list
, set
, 和 tuple
的替代選擇。
創(chuàng)建命名元組子類(lèi)的工廠函數(shù) |
|
類(lèi)似列表(list)的容器,實(shí)現(xiàn)了在兩端快速添加(append)和彈出(pop) |
|
類(lèi)似字典(dict)的容器類(lèi),將多個(gè)映射集合到一個(gè)視圖里面 |
|
字典的子類(lèi),提供了可哈希對(duì)象的計(jì)數(shù)功能 |
|
字典的子類(lèi),保存了他們被添加的順序 |
|
字典的子類(lèi),提供了一個(gè)工廠函數(shù),為字典查詢(xún)提供一個(gè)默認(rèn)值 |
|
封裝了字典對(duì)象,簡(jiǎn)化了字典子類(lèi)化 |
|
封裝了列表對(duì)象,簡(jiǎn)化了列表子類(lèi)化 |
|
封裝了字符串對(duì)象,簡(jiǎn)化了字符串子類(lèi)化 |
ChainMap
對(duì)象?
3.3 新版功能.
一個(gè) ChainMap
類(lèi)是為了將多個(gè)映射快速的鏈接到一起,這樣它們就可以作為一個(gè)單元處理。它通常比創(chuàng)建一個(gè)新字典和多次調(diào)用 update()
要快很多。
這個(gè)類(lèi)可以用于模擬嵌套作用域,并且在模版化的時(shí)候比較有用。
- class collections.ChainMap(*maps)?
一個(gè)
ChainMap
將多個(gè)字典或者其他映射組合在一起,創(chuàng)建一個(gè)單獨(dú)的可更新的視圖。 如果沒(méi)有 maps 被指定,就提供一個(gè)默認(rèn)的空字典,這樣一個(gè)新鏈至少有一個(gè)映射。底層映射被存儲(chǔ)在一個(gè)列表中。這個(gè)列表是公開(kāi)的,可以通過(guò) maps 屬性存取和更新。沒(méi)有其他的狀態(tài)。
搜索查詢(xún)底層映射,直到一個(gè)鍵被找到。不同的是,寫(xiě),更新和刪除只操作第一個(gè)映射。
一個(gè)
ChainMap
通過(guò)引用合并底層映射。 所以,如果一個(gè)底層映射更新了,這些更改會(huì)反映到ChainMap
。支持所有常用字典方法。另外還有一個(gè) maps 屬性(attribute),一個(gè)創(chuàng)建子上下文的方法(method), 一個(gè)存取它們首個(gè)映射的屬性(property):
- maps?
一個(gè)可以更新的映射列表。這個(gè)列表是按照第一次搜索到最后一次搜索的順序組織的。它是僅有的存儲(chǔ)狀態(tài),可以被修改。列表最少包含一個(gè)映射。
- new_child(m=None, **kwargs)?
返回一個(gè)新的
ChainMap
,其中包含一個(gè)新的映射,后面跟隨當(dāng)前實(shí)例中的所有映射。 如果指定了m
,它會(huì)成為新的映射加在映射列表的前面;如果未指定,則會(huì)使用一個(gè)空字典,因此調(diào)用d.new_child()
就等價(jià)于ChainMap({}, *d.maps)
。 如果指定了任何關(guān)鍵字參數(shù),它們會(huì)更新所傳入的映射或新的空字典。 此方法被用于創(chuàng)建子上下文,它可在不改變?nèi)魏紊霞?jí)映射的情況下被更新。在 3.4 版更改: 添加了
m
可選參數(shù)。在 3.10 版更改: 增加了對(duì)關(guān)鍵字參數(shù)的支持。
- parents?
屬性返回一個(gè)新的
ChainMap
包含所有的當(dāng)前實(shí)例的映射,除了第一個(gè)。這樣可以在搜索的時(shí)候跳過(guò)第一個(gè)映射。 使用的場(chǎng)景類(lèi)似在 nested scopes 嵌套作用域中使用nonlocal
關(guān)鍵詞。用例也可以類(lèi)比內(nèi)建函數(shù)super()
。一個(gè)d.parents
的引用等價(jià)于ChainMap(*d.maps[1:])
。
注意,一個(gè)
ChainMap()
的迭代順序是通過(guò)從后往前掃描所有映射來(lái)確定的:>>> baseline = {'music': 'bach', 'art': 'rembrandt'} >>> adjustments = {'art': 'van gogh', 'opera': 'carmen'} >>> list(ChainMap(adjustments, baseline)) ['music', 'art', 'opera']
這給出了與
dict.update()
調(diào)用序列相同的順序,從最后一個(gè)映射開(kāi)始:>>> combined = baseline.copy() >>> combined.update(adjustments) >>> list(combined) ['music', 'art', 'opera']
在 3.9 版更改: 增加了對(duì)
|
和|=
運(yùn)算符的支持,相關(guān)說(shuō)明見(jiàn) PEP 584。
參見(jiàn)
MultiContext class 在 Enthought CodeTools package 有支持寫(xiě)映射的選項(xiàng)。
Django 中用于模板的 Context class 是只讀的映射鏈。 它還具有上下文推送和彈出特性,類(lèi)似于
new_child()
方法和parents
特征屬性。Nested Contexts recipe 提供了是否對(duì)第一個(gè)映射或其他映射進(jìn)行寫(xiě)和其他修改的選項(xiàng)。
一個(gè) 極簡(jiǎn)的只讀版 Chainmap.
ChainMap
例子和方法?
這一節(jié)提供了多個(gè)使用鏈映射的案例。
模擬Python內(nèi)部lookup鏈的例子
import builtins
pylookup = ChainMap(locals(), globals(), vars(builtins))
讓用戶(hù)指定的命令行參數(shù)優(yōu)先于環(huán)境變量,優(yōu)先于默認(rèn)值的例子
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
類(lèi)模擬嵌套上下文的例子
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
類(lèi)只更新鏈中的第一個(gè)映射,但lookup會(huì)搜索整個(gè)鏈。 然而,如果需要深度寫(xiě)和刪除,也可以很容易的通過(guò)定義一個(gè)子類(lèi)來(lái)實(shí)現(xiàn)它
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
對(duì)象?
一個(gè)計(jì)數(shù)器工具提供快速和方便的計(jì)數(shù)。比如
>>> # 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([iterable-or-mapping])?
一個(gè)
Counter
是一個(gè)dict
的子類(lèi),用于計(jì)數(shù)可哈希對(duì)象。它是一個(gè)集合,元素像字典鍵(key)一樣存儲(chǔ),它們的計(jì)數(shù)存儲(chǔ)為值。計(jì)數(shù)可以是任何整數(shù)值,包括0和負(fù)數(shù)。Counter
類(lèi)有點(diǎn)像其他語(yǔ)言中的 bags或multisets。元素從一個(gè) iterable 被計(jì)數(shù)或從其他的 mapping (or counter)初始化:
>>> c = Counter() # a new, empty counter >>> c = Counter('gallahad') # a new counter from an iterable >>> c = Counter({'red': 4, 'blue': 2}) # a new counter from a mapping >>> c = Counter(cats=4, dogs=8) # a new counter from keyword args
Counter對(duì)象有一個(gè)字典接口,如果引用的鍵沒(méi)有任何記錄,就返回一個(gè)0,而不是彈出一個(gè)
KeyError
:>>> c = Counter(['eggs', 'ham']) >>> c['bacon'] # count of a missing element is zero 0
設(shè)置一個(gè)計(jì)數(shù)為0不會(huì)從計(jì)數(shù)器中移去一個(gè)元素。使用
del
來(lái)刪除它:>>> c['sausage'] = 0 # counter entry with a zero count >>> del c['sausage'] # del actually removes the entry
3.1 新版功能.
在 3.7 版更改: As a
dict
subclass,Counter
inherited the capability to remember insertion order. Math operations on Counter objects also preserve order. Results are ordered according to when an element is first encountered in the left operand and then by the order encountered in the right operand.Counter objects support additional methods beyond those available for all dictionaries:
- elements()?
返回一個(gè)迭代器,其中每個(gè)元素將重復(fù)出現(xiàn)計(jì)數(shù)值所指定次。 元素會(huì)按首次出現(xiàn)的順序返回。 如果一個(gè)元素的計(jì)數(shù)值小于一,
elements()
將會(huì)忽略它。>>> c = Counter(a=4, b=2, c=0, d=-2) >>> sorted(c.elements()) ['a', 'a', 'a', 'a', 'b', 'b']
- most_common([n])?
返回一個(gè)列表,其中包含 n 個(gè)最常見(jiàn)的元素及出現(xiàn)次數(shù),按常見(jiàn)程度由高到低排序。 如果 n 被省略或?yàn)?
None
,most_common()
將返回計(jì)數(shù)器中的 所有 元素。 計(jì)數(shù)值相等的元素按首次出現(xiàn)的順序排序:>>> Counter('abracadabra').most_common(3) [('a', 5), ('b', 2), ('r', 2)]
- subtract([iterable-or-mapping])?
從 迭代對(duì)象 或 映射對(duì)象 減去元素。像
dict.update()
但是是減去,而不是替換。輸入和輸出都可以是0或者負(fù)數(shù)。>>> c = Counter(a=4, b=2, c=0, d=-2) >>> d = Counter(a=1, b=2, c=3, d=4) >>> c.subtract(d) >>> c Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})
3.2 新版功能.
- total()?
計(jì)算總計(jì)數(shù)值。
>>> c = Counter(a=10, b=5, c=0) >>> c.total() 15
3.10 新版功能.
通常字典方法都可用于
Counter
對(duì)象,除了有兩個(gè)方法工作方式與字典并不相同。- update([iterable-or-mapping])?
從 迭代對(duì)象 計(jì)數(shù)元素或者 從另一個(gè) 映射對(duì)象 (或計(jì)數(shù)器) 添加。 像
dict.update()
但是是加上,而不是替換。另外,迭代對(duì)象 應(yīng)該是序列元素,而不是一個(gè)(key, value)
對(duì)。
計(jì)數(shù)對(duì)象支持相等性、子集和超集關(guān)系等富比較運(yùn)算符: ==
, !=
, <
, <=
, >
, >=
。 所有這些檢測(cè)會(huì)將不存在的元素當(dāng)作計(jì)數(shù)值為零,因此 Counter(a=1) == Counter(a=1, b=0)
將返回真值。
3.10 新版功能: Rich comparison operations were added.
在 3.10 版更改: 在相等性檢測(cè)中,不存在的元素會(huì)被當(dāng)作計(jì)數(shù)值為零。 在此之前,Counter(a=3)
和 Counter(a=3, b=0)
會(huì)被視為不同。
Counter
對(duì)象的常用案例
c.total() # total of all counts
c.clear() # reset all counts
list(c) # list unique elements
set(c) # convert to a set
dict(c) # convert to a regular dictionary
c.items() # convert to a list of (elem, cnt) pairs
Counter(dict(list_of_pairs)) # convert from a list of (elem, cnt) pairs
c.most_common()[:-n-1:-1] # n least common elements
+c # remove zero and negative counts
Several mathematical operations are provided for combining Counter
objects to produce multisets (counters that have counts greater than zero).
Addition and subtraction combine counters by adding or subtracting the counts
of corresponding elements. Intersection and union return the minimum and
maximum of corresponding counts. Equality and inclusion compare
corresponding counts. Each operation can accept inputs with signed
counts, but the output will exclude results with counts of zero or less.
>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d # add two counters together: c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d # subtract (keeping only positive counts)
Counter({'a': 2})
>>> c & d # intersection: min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d # union: max(c[x], d[x])
Counter({'a': 3, 'b': 2})
>>> c == d # equality: c[x] == d[x]
False
>>> c <= d # inclusion: c[x] <= d[x]
False
單目加和減(一元操作符)意思是從空計(jì)數(shù)器加或者減去。
>>> c = Counter(a=2, b=-4)
>>> +c
Counter({'a': 2})
>>> -c
Counter({'b': 4})
3.3 新版功能: 添加了對(duì)一元加,一元減和位置集合操作的支持。
備注
計(jì)數(shù)器主要是為了表達(dá)運(yùn)行的正的計(jì)數(shù)而設(shè)計(jì);但是,小心不要預(yù)先排除負(fù)數(shù)或者其他類(lèi)型。為了幫助這些用例,這一節(jié)記錄了最小范圍和類(lèi)型限制。
Counter
類(lèi)是一個(gè)字典的子類(lèi),不限制鍵和值。值用于表示計(jì)數(shù),但你實(shí)際上 可以 存儲(chǔ)任何其他值。most_common()
方法在值需要排序的時(shí)候用。原地操作比如
c[key] += 1
, 值類(lèi)型只需要支持加和減。 所以分?jǐn)?shù),小數(shù),和十進(jìn)制都可以用,負(fù)值也可以支持。這兩個(gè)方法update()
和subtract()
的輸入和輸出也一樣支持負(fù)數(shù)和0。Multiset多集合方法只為正值的使用情況設(shè)計(jì)。輸入可以是負(fù)數(shù)或者0,但只輸出計(jì)數(shù)為正的值。沒(méi)有類(lèi)型限制,但值類(lèi)型需要支持加,減和比較操作。
elements()
方法要求正整數(shù)計(jì)數(shù)。忽略0和負(fù)數(shù)計(jì)數(shù)。
參見(jiàn)
Bag class 在 Smalltalk。
Wikipedia 鏈接 Multisets.
C++ multisets 教程和例子。
數(shù)學(xué)操作和多集合用例,參考 Knuth, Donald. The Art of Computer Programming Volume II, Section 4.6.3, Exercise 19 。
在給定數(shù)量和集合元素枚舉所有不同的多集合,參考
itertools.combinations_with_replacement()
map(Counter, combinations_with_replacement('ABC', 2)) # --> AA AB AC BB BC CC
deque
對(duì)象?
- class collections.deque([iterable[, maxlen]])?
返回一個(gè)新的雙向隊(duì)列對(duì)象,從左到右初始化(用方法
append()
) ,從 iterable (迭代對(duì)象) 數(shù)據(jù)創(chuàng)建。如果 iterable 沒(méi)有指定,新隊(duì)列為空。Deque隊(duì)列是由?;蛘遯ueue隊(duì)列生成的(發(fā)音是 “deck”,”double-ended queue”的簡(jiǎn)稱(chēng))。Deque 支持線(xiàn)程安全,內(nèi)存高效添加(append)和彈出(pop),從兩端都可以,兩個(gè)方向的大概開(kāi)銷(xiāo)都是 O(1) 復(fù)雜度。
雖然
list
對(duì)象也支持類(lèi)似操作,不過(guò)這里優(yōu)化了定長(zhǎng)操作和pop(0)
和insert(0, v)
的開(kāi)銷(xiāo)。它們引起 O(n) 內(nèi)存移動(dòng)的操作,改變底層數(shù)據(jù)表達(dá)的大小和位置。如果 maxlen 沒(méi)有指定或者是
None
,deques 可以增長(zhǎng)到任意長(zhǎng)度。否則,deque就限定到指定最大長(zhǎng)度。一旦限定長(zhǎng)度的deque滿(mǎn)了,當(dāng)新項(xiàng)加入時(shí),同樣數(shù)量的項(xiàng)就從另一端彈出。限定長(zhǎng)度deque提供類(lèi)似Unix filtertail
的功能。它們同樣可以用與追蹤最近的交換和其他數(shù)據(jù)池活動(dòng)。雙向隊(duì)列(deque)對(duì)象支持以下方法:
- append(x)?
添加 x 到右端。
- appendleft(x)?
添加 x 到左端。
- clear()?
移除所有元素,使其長(zhǎng)度為0.
- copy()?
創(chuàng)建一份淺拷貝。
3.5 新版功能.
- count(x)?
計(jì)算 deque 中元素等于 x 的個(gè)數(shù)。
3.2 新版功能.
- extend(iterable)?
擴(kuò)展deque的右側(cè),通過(guò)添加iterable參數(shù)中的元素。
- extendleft(iterable)?
擴(kuò)展deque的左側(cè),通過(guò)添加iterable參數(shù)中的元素。注意,左添加時(shí),在結(jié)果中iterable參數(shù)中的順序?qū)⒈环催^(guò)來(lái)添加。
- index(x[, start[, stop]])?
返回 x 在 deque 中的位置(在索引 start 之后,索引 stop 之前)。 返回第一個(gè)匹配項(xiàng),如果未找到則引發(fā)
ValueError
。3.5 新版功能.
- insert(i, x)?
在位置 i 插入 x 。
如果插入會(huì)導(dǎo)致一個(gè)限長(zhǎng) deque 超出長(zhǎng)度 maxlen 的話(huà),就引發(fā)一個(gè)
IndexError
。3.5 新版功能.
- pop()?
移去并且返回一個(gè)元素,deque 最右側(cè)的那一個(gè)。 如果沒(méi)有元素的話(huà),就引發(fā)一個(gè)
IndexError
。
- popleft()?
移去并且返回一個(gè)元素,deque 最左側(cè)的那一個(gè)。 如果沒(méi)有元素的話(huà),就引發(fā)
IndexError
。
- remove(value)?
移除找到的第一個(gè) value。 如果沒(méi)有的話(huà)就引發(fā)
ValueError
。
- reverse()?
將deque逆序排列。返回
None
。3.2 新版功能.
- rotate(n=1)?
向右循環(huán)移動(dòng) n 步。 如果 n 是負(fù)數(shù),就向左循環(huán)。
如果deque不是空的,向右循環(huán)移動(dòng)一步就等價(jià)于
d.appendleft(d.pop())
, 向左循環(huán)一步就等價(jià)于d.append(d.popleft())
。
Deque對(duì)象同樣提供了一個(gè)只讀屬性:
- maxlen?
Deque的最大尺寸,如果沒(méi)有限定的話(huà)就是
None
。3.1 新版功能.
除了以上操作,deque 還支持迭代、封存、len(d)
、reversed(d)
、copy.copy(d)
、copy.deepcopy(d)
、成員檢測(cè)運(yùn)算符 in
以及下標(biāo)引用例如通過(guò) d[0]
訪問(wèn)首個(gè)元素等。 索引訪問(wèn)在兩端的復(fù)雜度均為 O(1) 但在中間則會(huì)低至 O(n)。 如需快速隨機(jī)訪問(wèn),請(qǐng)改用列表。
Deque從版本3.5開(kāi)始支持 __add__()
, __mul__()
, 和 __imul__()
。
示例:
>>> from collections import deque
>>> d = deque('ghi') # make a new deque with three items
>>> for elem in d: # iterate over the deque's elements
... print(elem.upper())
G
H
I
>>> d.append('j') # add a new entry to the right side
>>> d.appendleft('f') # add a new entry to the left side
>>> d # show the representation of the deque
deque(['f', 'g', 'h', 'i', 'j'])
>>> d.pop() # return and remove the rightmost item
'j'
>>> d.popleft() # return and remove the leftmost item
'f'
>>> list(d) # list the contents of the deque
['g', 'h', 'i']
>>> d[0] # peek at leftmost item
'g'
>>> d[-1] # peek at rightmost item
'i'
>>> list(reversed(d)) # list the contents of a deque in reverse
['i', 'h', 'g']
>>> 'h' in d # search the deque
True
>>> d.extend('jkl') # add multiple elements at once
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> d.rotate(1) # right rotation
>>> d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
>>> d.rotate(-1) # left rotation
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> deque(reversed(d)) # make a new deque in reverse order
deque(['l', 'k', 'j', 'i', 'h', 'g'])
>>> d.clear() # empty the deque
>>> d.pop() # cannot pop from an empty deque
Traceback (most recent call last):
File "<pyshell#6>", line 1, in -toplevel-
d.pop()
IndexError: pop from an empty deque
>>> d.extendleft('abc') # extendleft() reverses the input order
>>> d
deque(['c', 'b', 'a'])
deque
用法?
這一節(jié)展示了deque的多種用法。
限長(zhǎng)deque提供了類(lèi)似Unix tail
過(guò)濾功能
def tail(filename, n=10):
'Return the last n lines of a file'
with open(filename) as f:
return deque(f, n)
另一個(gè)用法是維護(hù)一個(gè)近期添加元素的序列,通過(guò)從右邊添加和從左邊彈出
def moving_average(iterable, n=3):
# moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0
# http://en.wikipedia.org/wiki/Moving_average
it = iter(iterable)
d = deque(itertools.islice(it, n-1))
d.appendleft(0)
s = sum(d)
for elem in it:
s += elem - d.popleft()
d.append(elem)
yield s / n
一個(gè) 輪詢(xún)調(diào)度器 可以通過(guò)在 deque
中放入迭代器來(lái)實(shí)現(xiàn)。值從當(dāng)前迭代器的位置0被取出并暫存(yield)。 如果這個(gè)迭代器消耗完畢,就用 popleft()
將其從對(duì)列中移去;否則,就通過(guò) rotate()
將它移到隊(duì)列的末尾
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
iterators = deque(map(iter, iterables))
while iterators:
try:
while True:
yield next(iterators[0])
iterators.rotate(-1)
except StopIteration:
# Remove an exhausted iterator.
iterators.popleft()
rotate()
方法提供了一種方式來(lái)實(shí)現(xiàn) deque
切片和刪除。 例如, 一個(gè)純的Python del d[n]
實(shí)現(xiàn)依賴(lài)于 rotate()
來(lái)定位要彈出的元素
def delete_nth(d, n):
d.rotate(-n)
d.popleft()
d.rotate(n)
要實(shí)現(xiàn) deque
切片, 使用一個(gè)類(lèi)似的方法,應(yīng)用 rotate()
將目標(biāo)元素放到左邊。通過(guò) popleft()
移去老的條目(entries),通過(guò) extend()
添加新的條目, 然后反向 rotate。這個(gè)方法可以最小代價(jià)實(shí)現(xiàn)命令式的棧操作,諸如 dup
, drop
, swap
, over
, pick
, rot
, 和 roll
。
defaultdict
對(duì)象?
- class collections.defaultdict(default_factory=None, /[, ...])?
返回一個(gè)新的類(lèi)似字典的對(duì)象。
defaultdict
是內(nèi)置dict
類(lèi)的子類(lèi)。 它重載了一個(gè)方法并添加了一個(gè)可寫(xiě)的實(shí)例變量。 其余的功能與dict
類(lèi)相同因而不在此文檔中寫(xiě)明。本對(duì)象包含一個(gè)名為
default_factory
的屬性,構(gòu)造時(shí),第一個(gè)參數(shù)用于為該屬性提供初始值,默認(rèn)為None
。所有其他參數(shù)(包括關(guān)鍵字參數(shù))都相當(dāng)于傳遞給dict
的構(gòu)造函數(shù)。defaultdict
對(duì)象除了支持標(biāo)準(zhǔn)dict
的操作,還支持以下方法作為擴(kuò)展:- __missing__(key)?
如果
default_factory
屬性為None
,則調(diào)用本方法會(huì)拋出KeyError
異常,附帶參數(shù) key。如果
default_factory
不為None
,則它會(huì)被(不帶參數(shù)地)調(diào)用來(lái)為 key 提供一個(gè)默認(rèn)值,這個(gè)值和 key 作為一對(duì)鍵值對(duì)被插入到字典中,并作為本方法的返回值返回。如果調(diào)用
default_factory
時(shí)拋出了異常,這個(gè)異常會(huì)原封不動(dòng)地向外層傳遞。在無(wú)法找到所需鍵值時(shí),本方法會(huì)被
dict
中的__getitem__()
方法調(diào)用。無(wú)論本方法返回了值還是拋出了異常,都會(huì)被__getitem__()
傳遞。注意,
__missing__()
不會(huì) 被__getitem__()
以外的其他方法調(diào)用。意味著get()
會(huì)像正常的 dict 那樣返回None
,而不是使用default_factory
。
defaultdict
對(duì)象支持以下實(shí)例變量:- default_factory?
本屬性由
__missing__()
方法來(lái)調(diào)用。如果構(gòu)造對(duì)象時(shí)提供了第一個(gè)參數(shù),則本屬性會(huì)被初始化成那個(gè)參數(shù),如果未提供第一個(gè)參數(shù),則本屬性為None
。
在 3.9 版更改: 增加了合并 (
|
) 與更新 (|=
) 運(yùn)算符,相關(guān)說(shuō)明見(jiàn) PEP 584。
defaultdict
例子?
使用 list
作為 default_factory
,很輕松地將(鍵-值對(duì)組成的)序列轉(zhuǎn)換為(鍵-列表組成的)字典:
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
... d[k].append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
當(dāng)每個(gè)鍵第一次遇見(jiàn)時(shí),它還沒(méi)有在字典里面,所以自動(dòng)創(chuàng)建該條目,即調(diào)用 default_factory
方法,返回一個(gè)空的 list
。 list.append()
操作添加值到這個(gè)新的列表里。當(dāng)再次存取該鍵時(shí),就正常操作,list.append()
添加另一個(gè)值到列表中。這個(gè)計(jì)數(shù)比它的等價(jià)方法 dict.setdefault()
要快速和簡(jiǎn)單:
>>> d = {}
>>> for k, v in s:
... d.setdefault(k, []).append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
設(shè)置 default_factory
為 int
,使 defaultdict
用于計(jì)數(shù)(類(lèi)似其他語(yǔ)言中的 bag 或 multiset):
>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
... d[k] += 1
...
>>> sorted(d.items())
[('i', 4), ('m', 1), ('p', 2), ('s', 4)]
當(dāng)一個(gè)字母首次遇到時(shí),它會(huì)查詢(xún)失敗,則 default_factory
會(huì)調(diào)用 int()
來(lái)提供一個(gè)整數(shù) 0 作為默認(rèn)值。后續(xù)的自增操作建立起對(duì)每個(gè)字母的計(jì)數(shù)。
函數(shù) int()
總是返回 0,這是常數(shù)函數(shù)的特殊情況。一個(gè)更快和靈活的方法是使用 lambda 函數(shù),可以提供任何常量值(不只是0):
>>> def constant_factory(value):
... return lambda: value
>>> d = defaultdict(constant_factory('<missing>'))
>>> d.update(name='John', action='ran')
>>> '%(name)s %(action)s to %(object)s' % d
'John ran to <missing>'
設(shè)置 default_factory
為 set
使 defaultdict
用于構(gòu)建 set 集合:
>>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
>>> d = defaultdict(set)
>>> for k, v in s:
... d[k].add(v)
...
>>> sorted(d.items())
[('blue', {2, 4}), ('red', {1, 3})]
namedtuple()
命名元組的工廠函數(shù)?
命名元組賦予每個(gè)位置一個(gè)含義,提供可讀性和自文檔性。它們可以用于任何普通元組,并添加了通過(guò)名字獲取值的能力,通過(guò)索引值也是可以的。
- collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)?
返回一個(gè)新的元組子類(lèi),名為 typename 。這個(gè)新的子類(lèi)用于創(chuàng)建類(lèi)元組的對(duì)象,可以通過(guò)字段名來(lái)獲取屬性值,同樣也可以通過(guò)索引和迭代獲取值。子類(lèi)實(shí)例同樣有文檔字符串(類(lèi)名和字段名)另外一個(gè)有用的
__repr__()
方法,以name=value
格式列明了元組內(nèi)容。field_names 是一個(gè)像
[‘x’, ‘y’]
一樣的字符串序列。另外 field_names 可以是一個(gè)純字符串,用空白或逗號(hào)分隔開(kāi)元素名,比如'x y'
或者'x, y'
。任何有效的Python 標(biāo)識(shí)符都可以作為字段名,除了下劃線(xiàn)開(kāi)頭的那些。有效標(biāo)識(shí)符由字母,數(shù)字,下劃線(xiàn)組成,但首字母不能是數(shù)字或下劃線(xiàn),另外不能是關(guān)鍵詞
keyword
比如 class, for, return, global, pass, 或 raise 。如果 rename 為真, 無(wú)效字段名會(huì)自動(dòng)轉(zhuǎn)換成位置名。比如
['abc', 'def', 'ghi', 'abc']
轉(zhuǎn)換成['abc', '_1', 'ghi', '_3']
, 消除關(guān)鍵詞def
和重復(fù)字段名abc
。defaults 可以為
None
或者是一個(gè)默認(rèn)值的 iterable 。如果一個(gè)默認(rèn)值域必須跟其他沒(méi)有默認(rèn)值的域在一起出現(xiàn),defaults 就應(yīng)用到最右邊的參數(shù)。比如如果域名['x', 'y', 'z']
和默認(rèn)值(1, 2)
,那么x
就必須指定一個(gè)參數(shù)值 ,y
默認(rèn)值1
,z
默認(rèn)值2
。如果 module 值有定義,命名元組的
__module__
屬性值就被設(shè)置。命名元組實(shí)例沒(méi)有字典,所以它們要更輕量,并且占用更小內(nèi)存。
要支持封存操作,應(yīng)當(dāng)將命名元組類(lèi)賦值給一個(gè)匹配 typename 的變量。
在 3.1 版更改: 添加了對(duì) rename 的支持。
在 3.6 版更改: verbose 和 rename 參數(shù)成為 僅限關(guān)鍵字參數(shù).
在 3.6 版更改: 添加了 module 參數(shù)。
在 3.7 版更改: 移除了 verbose 形參和
_source
屬性。在 3.7 版更改: 添加了 defaults 參數(shù)和
_field_defaults
屬性。
>>> # Basic example
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22) # instantiate with positional or keyword arguments
>>> p[0] + p[1] # indexable like the plain tuple (11, 22)
33
>>> x, y = p # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y # fields also accessible by name
33
>>> p # readable __repr__ with a name=value style
Point(x=11, y=22)
命名元組尤其有用于賦值 csv
sqlite3
模塊返回的元組
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
print(emp.name, emp.title)
import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
print(emp.name, emp.title)
除了繼承元組的方法,命名元組還支持三個(gè)額外的方法和兩個(gè)屬性。為了防止字段名沖突,方法和屬性以下劃線(xiàn)開(kāi)始。
- classmethod somenamedtuple._make(iterable)?
類(lèi)方法從存在的序列或迭代實(shí)例創(chuàng)建一個(gè)新實(shí)例。
>>> t = [11, 22] >>> Point._make(t) Point(x=11, y=22)
- somenamedtuple._asdict()?
返回一個(gè)新的
dict
,它將字段名稱(chēng)映射到它們對(duì)應(yīng)的值:>>> p = Point(x=11, y=22) >>> p._asdict() {'x': 11, 'y': 22}
在 3.1 版更改: 返回一個(gè)
OrderedDict
而不是dict
。在 3.8 版更改: 返回一個(gè)常規(guī)
dict
而不是OrderedDict
。 因?yàn)樽?Python 3.7 起,常規(guī)字典已經(jīng)保證有序。 如果需要OrderedDict
的額外特性,推薦的解決方案是將結(jié)果轉(zhuǎn)換為需要的類(lèi)型:OrderedDict(nt._asdict())
。
- somenamedtuple._replace(**kwargs)?
返回一個(gè)新的命名元組實(shí)例,并將指定域替換為新的值
>>> p = Point(x=11, y=22) >>> p._replace(x=33) Point(x=33, y=22) >>> for partnum, record in inventory.items(): ... inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now())
- somenamedtuple._fields?
字符串元組列出了字段名。用于提醒和從現(xiàn)有元組創(chuàng)建一個(gè)新的命名元組類(lèi)型。
>>> p._fields # view the field names ('x', 'y') >>> Color = namedtuple('Color', 'red green blue') >>> Pixel = namedtuple('Pixel', Point._fields + Color._fields) >>> Pixel(11, 22, 128, 255, 0) Pixel(x=11, y=22, red=128, green=255, blue=0)
- somenamedtuple._field_defaults?
字典將字段名稱(chēng)映射到默認(rèn)值。
>>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0]) >>> Account._field_defaults {'balance': 0} >>> Account('premium') Account(type='premium', balance=0)
要獲取這個(gè)名字域的值,使用 getattr()
函數(shù) :
>>> getattr(p, 'x')
11
轉(zhuǎn)換一個(gè)字典到命名元組,使用 ** 兩星操作符 (所述如 解包實(shí)參列表):
>>> d = {'x': 11, 'y': 22}
>>> Point(**d)
Point(x=11, y=22)
因?yàn)橐粋€(gè)命名元組是一個(gè)正常的Python類(lèi),它可以很容易的通過(guò)子類(lèi)更改功能。這里是如何添加一個(gè)計(jì)算域和定寬輸出打印格式:
>>> class Point(namedtuple('Point', ['x', 'y'])):
... __slots__ = ()
... @property
... def hypot(self):
... return (self.x ** 2 + self.y ** 2) ** 0.5
... def __str__(self):
... return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot)
>>> for p in Point(3, 4), Point(14, 5/7):
... print(p)
Point: x= 3.000 y= 4.000 hypot= 5.000
Point: x=14.000 y= 0.714 hypot=14.018
上面的子類(lèi)設(shè)置 __slots__
為一個(gè)空元組。通過(guò)阻止創(chuàng)建實(shí)例字典保持了較低的內(nèi)存開(kāi)銷(xiāo)。
子類(lèi)化對(duì)于添加和存儲(chǔ)新的名字域是無(wú)效的。應(yīng)當(dāng)通過(guò) _fields
創(chuàng)建一個(gè)新的命名元組來(lái)實(shí)現(xiàn)它:
>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))
文檔字符串可以自定義,通過(guò)直接賦值給 __doc__
屬性:
>>> Book = namedtuple('Book', ['id', 'title', 'authors'])
>>> Book.__doc__ += ': Hardcover book in active collection'
>>> Book.id.__doc__ = '13-digit ISBN'
>>> Book.title.__doc__ = 'Title of first printing'
>>> Book.authors.__doc__ = 'List of authors sorted by last name'
在 3.5 版更改: 文檔字符串屬性變成可寫(xiě)。
參見(jiàn)
請(qǐng)參閱
typing.NamedTuple
,以獲取為命名元組添加類(lèi)型提示的方法。 它還使用class
關(guān)鍵字提供了一種優(yōu)雅的符號(hào):class Component(NamedTuple): part_number: int weight: float description: Optional[str] = None
對(duì)于以字典為底層的可變域名, 參考
types.SimpleNamespace()
。dataclasses
模塊提供了一個(gè)裝飾器和一些函數(shù),用于自動(dòng)將生成的特殊方法添加到用戶(hù)定義的類(lèi)中。
OrderedDict
對(duì)象?
有序詞典就像常規(guī)詞典一樣,但有一些與排序操作相關(guān)的額外功能。由于內(nèi)置的 dict
類(lèi)獲得了記住插入順序的能力(在 Python 3.7 中保證了這種新行為),它們變得不那么重要了。
一些與 dict
的不同仍然存在:
常規(guī)的
dict
被設(shè)計(jì)為非常擅長(zhǎng)映射操作。 跟蹤插入順序是次要的。OrderedDict
旨在擅長(zhǎng)重新排序操作。 空間效率、迭代速度和更新操作的性能是次要的。The
OrderedDict
algorithm can handle frequent reordering operations better thandict
. As shown in the recipes below, this makes it suitable for implementing various kinds of LRU caches.對(duì)于
OrderedDict
,相等操作檢查匹配順序。A regular
dict
can emulate the order sensitive equality test withp == q and all(k1 == k2 for k1, k2 in zip(p, q))
.OrderedDict
類(lèi)的popitem()
方法有不同的簽名。它接受一個(gè)可選參數(shù)來(lái)指定彈出哪個(gè)元素。A regular
dict
can emulate OrderedDict'sod.popitem(last=True)
withd.popitem()
which is guaranteed to pop the rightmost (last) item.A regular
dict
can emulate OrderedDict'sod.popitem(last=False)
with(k := next(iter(d)), d.pop(k))
which will return and remove the leftmost (first) item if it exists.OrderedDict
類(lèi)有一個(gè)move_to_end()
方法,可以有效地將元素移動(dòng)到任一端。A regular
dict
can emulate OrderedDict'sod.move_to_end(k, last=True)
withd[k] = d.pop(k)
which will move the key and its associated value to the rightmost (last) position.A regular
dict
does not have an efficient equivalent for OrderedDict'sod.move_to_end(k, last=False)
which moves the key and its associated value to the leftmost (first) position.Python 3.8之前,
dict
缺少__reversed__()
方法。
- class collections.OrderedDict([items])?
返回一個(gè)
dict
子類(lèi)的實(shí)例,它具有專(zhuān)門(mén)用于重新排列字典順序的方法。3.1 新版功能.
- popitem(last=True)?
有序字典的
popitem()
方法移除并返回一個(gè) (key, value) 鍵值對(duì)。 如果 last 值為真,則按 LIFO 后進(jìn)先出的順序返回鍵值對(duì),否則就按 FIFO 先進(jìn)先出的順序返回鍵值對(duì)。
- move_to_end(key, last=True)?
Move an existing key to either end of an ordered dictionary. The item is moved to the right end if last is true (the default) or to the beginning if last is false. Raises
KeyError
if the key does not exist:>>> d = OrderedDict.fromkeys('abcde') >>> d.move_to_end('b') >>> ''.join(d) 'acdeb' >>> d.move_to_end('b', last=False) >>> ''.join(d) 'bacde'
3.2 新版功能.
相對(duì)于通常的映射方法,有序字典還另外提供了逆序迭代的支持,通過(guò) reversed()
。
OrderedDict
之間的相等測(cè)試是順序敏感的,實(shí)現(xiàn)為 list(od1.items())==list(od2.items())
。 OrderedDict
對(duì)象和其他的 Mapping
的相等測(cè)試,是順序敏感的字典測(cè)試。這允許 OrderedDict
替換為任何字典可以使用的場(chǎng)所。
在 3.5 版更改: OrderedDict
的項(xiàng)(item),鍵(key)和值(value) 視圖 現(xiàn)在支持逆序迭代,通過(guò) reversed()
。
在 3.6 版更改: PEP 468 贊成將關(guān)鍵詞參數(shù)的順序保留, 通過(guò)傳遞給 OrderedDict
構(gòu)造器和它的 update()
方法。
在 3.9 版更改: 增加了合并 (|
) 與更新 (|=
) 運(yùn)算符,相關(guān)說(shuō)明見(jiàn) PEP 584。
OrderedDict
例子和用法?
創(chuàng)建記住鍵值 最后 插入順序的有序字典變體很簡(jiǎn)單。 如果新條目覆蓋現(xiàn)有條目,則原始插入位置將更改并移至末尾:
class LastUpdatedOrderedDict(OrderedDict):
'Store items in the order the keys were last added'
def __setitem__(self, key, value):
super().__setitem__(key, value)
self.move_to_end(key)
一個(gè) OrderedDict
對(duì)于實(shí)現(xiàn) functools.lru_cache()
的變體也很有用:
from time import time
class TimeBoundedLRU:
"LRU Cache that invalidates and refreshes old entries."
def __init__(self, func, maxsize=128, maxage=30):
self.cache = OrderedDict() # { args : (timestamp, result)}
self.func = func
self.maxsize = maxsize
self.maxage = maxage
def __call__(self, *args):
if args in self.cache:
self.cache.move_to_end(args)
timestamp, result = self.cache[args]
if time() - timestamp <= self.maxage:
return result
result = self.func(*args)
self.cache[args] = time(), result
if len(self.cache) > self.maxsize:
self.cache.popitem(0)
return result
class MultiHitLRUCache:
""" LRU cache that defers caching a result until
it has been requested multiple times.
To avoid flushing the LRU cache with one-time requests,
we don't cache until a request has been made more than once.
"""
def __init__(self, func, maxsize=128, maxrequests=4096, cache_after=1):
self.requests = OrderedDict() # { uncached_key : request_count }
self.cache = OrderedDict() # { cached_key : function_result }
self.func = func
self.maxrequests = maxrequests # max number of uncached requests
self.maxsize = maxsize # max number of stored return values
self.cache_after = cache_after
def __call__(self, *args):
if args in self.cache:
self.cache.move_to_end(args)
return self.cache[args]
result = self.func(*args)
self.requests[args] = self.requests.get(args, 0) + 1
if self.requests[args] <= self.cache_after:
self.requests.move_to_end(args)
if len(self.requests) > self.maxrequests:
self.requests.popitem(0)
else:
self.requests.pop(args, None)
self.cache[args] = result
if len(self.cache) > self.maxsize:
self.cache.popitem(0)
return result
UserDict
對(duì)象?
UserDict
類(lèi)是用作字典對(duì)象的外包裝。對(duì)這個(gè)類(lèi)的需求已部分由直接創(chuàng)建 dict
的子類(lèi)的功能所替代;不過(guò),這個(gè)類(lèi)處理起來(lái)更容易,因?yàn)榈讓拥淖值淇梢宰鳛閷傩詠?lái)訪問(wèn)。
UserList
對(duì)象?
這個(gè)類(lèi)封裝了列表對(duì)象。它是一個(gè)有用的基礎(chǔ)類(lèi),對(duì)于你想自定義的類(lèi)似列表的類(lèi),可以繼承和覆蓋現(xiàn)有的方法,也可以添加新的方法。這樣我們可以對(duì)列表添加新的行為。
對(duì)這個(gè)類(lèi)的需求已部分由直接創(chuàng)建 list
的子類(lèi)的功能所替代;不過(guò),這個(gè)類(lèi)處理起來(lái)更容易,因?yàn)榈讓拥牧斜砜梢宰鳛閷傩詠?lái)訪問(wèn)。
- class collections.UserList([list])?
模擬一個(gè)列表。這個(gè)實(shí)例的內(nèi)容被保存為一個(gè)正常列表,通過(guò)
UserList
的data
屬性存取。實(shí)例內(nèi)容被初始化為一個(gè) list 的copy,默認(rèn)為[]
空列表。 list 可以是迭代對(duì)象,比如一個(gè)Python列表,或者一個(gè)UserList
對(duì)象。UserList
提供了以下屬性作為可變序列的方法和操作的擴(kuò)展:
子類(lèi)化的要求: UserList
的子類(lèi)需要提供一個(gè)構(gòu)造器,可以無(wú)參數(shù)調(diào)用,或者一個(gè)參數(shù)調(diào)用。返回一個(gè)新序列的列表操作需要?jiǎng)?chuàng)建一個(gè)實(shí)現(xiàn)類(lèi)的實(shí)例。它假定了構(gòu)造器可以以一個(gè)參數(shù)進(jìn)行調(diào)用,這個(gè)參數(shù)是一個(gè)序列對(duì)象,作為數(shù)據(jù)源。
如果一個(gè)分離的類(lèi)不希望依照這個(gè)需求,所有的特殊方法就必須重寫(xiě);請(qǐng)參照源代碼進(jìn)行修改。
UserString
對(duì)象?
UserString
類(lèi)是用作字符串對(duì)象的外包裝。對(duì)這個(gè)類(lèi)的需求已部分由直接創(chuàng)建 str
的子類(lèi)的功能所替代;不過(guò),這個(gè)類(lèi)處理起來(lái)更容易,因?yàn)榈讓拥淖址梢宰鳛閷傩詠?lái)訪問(wèn)。
- class collections.UserString(seq)?
模擬一個(gè)字符串對(duì)象。這個(gè)實(shí)例對(duì)象的內(nèi)容保存為一個(gè)正常字符串,通過(guò)
UserString
的data
屬性存取。實(shí)例內(nèi)容初始化設(shè)置為 seq 的copy。seq 參數(shù)可以是任何可通過(guò)內(nèi)建str()
函數(shù)轉(zhuǎn)換為字符串的對(duì)象。UserString
提供了以下屬性作為字符串方法和操作的額外支持:- data?
一個(gè)真正的
str
對(duì)象用來(lái)存放UserString
類(lèi)的內(nèi)容。
在 3.5 版更改: 新方法
__getnewargs__
,__rmod__
,casefold
,format_map
,isprintable
, 和maketrans
。