collections --- 容器數(shù)據(jù)類型?

Source code: Lib/collections/__init__.py


這個(gè)模塊實(shí)現(xiàn)了特定目標(biāo)的容器,以提供Python標(biāo)準(zhǔn)內(nèi)建容器 dict , list , set , 和 tuple 的替代選擇。

namedtuple()

創(chuàng)建命名元組子類的工廠函數(shù)

deque

類似列表(list)的容器,實(shí)現(xiàn)了在兩端快速添加(append)和彈出(pop)

ChainMap

類似字典(dict)的容器類,將多個(gè)映射集合到一個(gè)視圖里面

Counter

字典的子類,提供了可哈希對(duì)象的計(jì)數(shù)功能

OrderedDict

字典的子類,保存了他們被添加的順序

defaultdict

字典的子類,提供了一個(gè)工廠函數(shù),為字典查詢提供一個(gè)默認(rèn)值

UserDict

封裝了字典對(duì)象,簡(jiǎn)化了字典子類化

UserList

封裝了列表對(duì)象,簡(jiǎn)化了列表子類化

UserString

封裝了字符串對(duì)象,簡(jiǎn)化了字符串子類化

ChainMap 對(duì)象?

3.3 新版功能.

一個(gè) ChainMap 類是為了將多個(gè)映射快速的鏈接到一起,這樣它們就可以作為一個(gè)單元處理。它通常比創(chuàng)建一個(gè)新字典和多次調(diào)用 update() 要快很多。

這個(gè)類可以用于模擬嵌套作用域,并且在模版化的時(shí)候比較有用。

class collections.ChainMap(*maps)?

一個(gè) ChainMap 將多個(gè)字典或者其他映射組合在一起,創(chuàng)建一個(gè)單獨(dú)的可更新的視圖。 如果沒有 maps 被指定,就提供一個(gè)默認(rèn)的空字典,這樣一個(gè)新鏈至少有一個(gè)映射。

底層映射被存儲(chǔ)在一個(gè)列表中。這個(gè)列表是公開的,可以通過 maps 屬性存取和更新。沒有其他的狀態(tài)。

搜索查詢底層映射,直到一個(gè)鍵被找到。不同的是,寫,更新和刪除只操作第一個(gè)映射。

一個(gè) ChainMap 通過引用合并底層映射。 所以,如果一個(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í)候跳過第一個(gè)映射。 使用的場(chǎng)景類似在 nested scopes 嵌套作用域中使用 nonlocal 關(guān)鍵詞。用例也可以類比內(nèi)建函數(shù) super() 。一個(gè) d.parents 的引用等價(jià)于 ChainMap(*d.maps[1:]) 。

注意,一個(gè) ChainMap() 的迭代順序是通過從后往前掃描所有映射來確定的:

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

這給出了與 dict.update() 調(diào)用序列相同的順序,從最后一個(gè)映射開始:

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

在 3.9 版更改: 增加了對(duì) ||= 運(yùn)算符的支持,相關(guān)說明見 PEP 584

參見

ChainMap 例子和方法?

這一節(jié)提供了多個(gè)使用鏈映射的案例。

模擬Python內(nèi)部lookup鏈的例子

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

讓用戶指定的命令行參數(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 類模擬嵌套上下文的例子

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 類只更新鏈中的第一個(gè)映射,但lookup會(huì)搜索整個(gè)鏈。 然而,如果需要深度寫和刪除,也可以很容易的通過定義一個(gè)子類來實(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 的子類,用于計(jì)數(shù)可哈希對(duì)象。它是一個(gè)集合,元素像字典鍵(key)一樣存儲(chǔ),它們的計(jì)數(shù)存儲(chǔ)為值。計(jì)數(shù)可以是任何整數(shù)值,包括0和負(fù)數(shù)。 Counter 類有點(diǎn)像其他語言中的 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è)字典接口,如果引用的鍵沒有任何記錄,就返回一個(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 來刪除它:

>>>
>>> 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è)最常見的元素及出現(xiàn)次數(shù),按常見程度由高到低排序。 如果 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è)方法工作方式與字典并不相同。

fromkeys(iterable)?

這個(gè)類方法沒有在 Counter 中實(shí)現(xiàn)。

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ù)或者其他類型。為了幫助這些用例,這一節(jié)記錄了最小范圍和類型限制。

  • Counter 類是一個(gè)字典的子類,不限制鍵和值。值用于表示計(jì)數(shù),但你實(shí)際上 可以 存儲(chǔ)任何其他值。

  • most_common() 方法在值需要排序的時(shí)候用。

  • 原地操作比如 c[key] += 1 , 值類型只需要支持加和減。 所以分?jǐn)?shù),小數(shù),和十進(jìn)制都可以用,負(fù)值也可以支持。這兩個(gè)方法 update()subtract() 的輸入和輸出也一樣支持負(fù)數(shù)和0。

  • Multiset多集合方法只為正值的使用情況設(shè)計(jì)。輸入可以是負(fù)數(shù)或者0,但只輸出計(jì)數(shù)為正的值。沒有類型限制,但值類型需要支持加,減和比較操作。

  • elements() 方法要求正整數(shù)計(jì)數(shù)。忽略0和負(fù)數(shù)計(jì)數(shù)。

參見

  • 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 沒有指定,新隊(duì)列為空。

Deque隊(duì)列是由?;蛘遯ueue隊(duì)列生成的(發(fā)音是 “deck”,”double-ended queue”的簡(jiǎn)稱)。Deque 支持線程安全,內(nèi)存高效添加(append)和彈出(pop),從兩端都可以,兩個(gè)方向的大概開銷都是 O(1) 復(fù)雜度。

雖然 list 對(duì)象也支持類似操作,不過這里優(yōu)化了定長(zhǎng)操作和 pop(0)insert(0, v) 的開銷。它們引起 O(n) 內(nèi)存移動(dòng)的操作,改變底層數(shù)據(jù)表達(dá)的大小和位置。

如果 maxlen 沒有指定或者是 None ,deques 可以增長(zhǎng)到任意長(zhǎng)度。否則,deque就限定到指定最大長(zhǎng)度。一旦限定長(zhǎng)度的deque滿了,當(dāng)新項(xiàng)加入時(shí),同樣數(shù)量的項(xiàng)就從另一端彈出。限定長(zhǎng)度deque提供類似Unix filter tail 的功能。它們同樣可以用與追蹤最近的交換和其他數(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è),通過添加iterable參數(shù)中的元素。

extendleft(iterable)?

擴(kuò)展deque的左側(cè),通過添加iterable參數(shù)中的元素。注意,左添加時(shí),在結(jié)果中iterable參數(shù)中的順序?qū)⒈环催^來添加。

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 的話,就引發(fā)一個(gè) IndexError。

3.5 新版功能.

pop()?

移去并且返回一個(gè)元素,deque 最右側(cè)的那一個(gè)。 如果沒有元素的話,就引發(fā)一個(gè) IndexError

popleft()?

移去并且返回一個(gè)元素,deque 最左側(cè)的那一個(gè)。 如果沒有元素的話,就引發(fā) IndexError。

remove(value)?

移除找到的第一個(gè) value。 如果沒有的話就引發(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的最大尺寸,如果沒有限定的話就是 None 。

3.1 新版功能.

除了以上操作,deque 還支持迭代、封存、len(d)、reversed(d)copy.copy(d)copy.deepcopy(d)、成員檢測(cè)運(yùn)算符 in 以及下標(biāo)引用例如通過 d[0] 訪問首個(gè)元素等。 索引訪問在兩端的復(fù)雜度均為 O(1) 但在中間則會(huì)低至 O(n)。 如需快速隨機(jī)訪問,請(qǐng)改用列表。

Deque從版本3.5開始支持 __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提供了類似Unix tail 過濾功能

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è)近期添加元素的序列,通過從右邊添加和從左邊彈出

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è) 輪詢調(diào)度器 可以通過在 deque 中放入迭代器來實(shí)現(xiàn)。值從當(dāng)前迭代器的位置0被取出并暫存(yield)。 如果這個(gè)迭代器消耗完畢,就用 popleft() 將其從對(duì)列中移去;否則,就通過 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() 方法提供了一種方式來實(shí)現(xiàn) deque 切片和刪除。 例如, 一個(gè)純的Python del d[n] 實(shí)現(xiàn)依賴于 rotate() 來定位要彈出的元素

def delete_nth(d, n):
    d.rotate(-n)
    d.popleft()
    d.rotate(n)

要實(shí)現(xiàn) deque 切片, 使用一個(gè)類似的方法,應(yīng)用 rotate() 將目標(biāo)元素放到左邊。通過 popleft() 移去老的條目(entries),通過 extend() 添加新的條目, 然后反向 rotate。這個(gè)方法可以最小代價(jià)實(shí)現(xiàn)命令式的棧操作,諸如 dup, drop, swap, over, pick, rot, 和 roll 。

defaultdict 對(duì)象?

class collections.defaultdict(default_factory=None, /[, ...])?

返回一個(gè)新的類似字典的對(duì)象。 defaultdict 是內(nèi)置 dict 類的子類。 它重載了一個(gè)方法并添加了一個(gè)可寫的實(shí)例變量。 其余的功能與 dict 類相同因而不在此文檔中寫明。

本對(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)用來為 key 提供一個(gè)默認(rèn)值,這個(gè)值和 key 作為一對(duì)鍵值對(duì)被插入到字典中,并作為本方法的返回值返回。

如果調(diào)用 default_factory 時(shí)拋出了異常,這個(gè)異常會(huì)原封不動(dòng)地向外層傳遞。

在無法找到所需鍵值時(shí),本方法會(huì)被 dict 中的 __getitem__() 方法調(diào)用。無論本方法返回了值還是拋出了異常,都會(huì)被 __getitem__() 傳遞。

注意,__missing__() 不會(huì)__getitem__() 以外的其他方法調(diào)用。意味著 get() 會(huì)像正常的 dict 那樣返回 None,而不是使用 default_factory。

defaultdict 對(duì)象支持以下實(shí)例變量:

default_factory?

本屬性由 __missing__() 方法來調(diào)用。如果構(gòu)造對(duì)象時(shí)提供了第一個(gè)參數(shù),則本屬性會(huì)被初始化成那個(gè)參數(shù),如果未提供第一個(gè)參數(shù),則本屬性為 None。

在 3.9 版更改: 增加了合并 (|) 與更新 (|=) 運(yùn)算符,相關(guā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è)鍵第一次遇見時(shí),它還沒有在字典里面,所以自動(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_factoryint,使 defaultdict 用于計(jì)數(shù)(類似其他語言中的 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ì)查詢失敗,則 default_factory 會(huì)調(diào)用 int() 來提供一個(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_factoryset 使 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è)含義,提供可讀性和自文檔性。它們可以用于任何普通元組,并添加了通過名字獲取值的能力,通過索引值也是可以的。

collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)?

返回一個(gè)新的元組子類,名為 typename 。這個(gè)新的子類用于創(chuàng)建類元組的對(duì)象,可以通過字段名來獲取屬性值,同樣也可以通過索引和迭代獲取值。子類實(shí)例同樣有文檔字符串(類名和字段名)另外一個(gè)有用的 __repr__() 方法,以 name=value 格式列明了元組內(nèi)容。

field_names 是一個(gè)像 [‘x’, ‘y’] 一樣的字符串序列。另外 field_names 可以是一個(gè)純字符串,用空白或逗號(hào)分隔開元素名,比如 'x y' 或者 'x, y' 。

任何有效的Python 標(biāo)識(shí)符都可以作為字段名,除了下劃線開頭的那些。有效標(biāo)識(shí)符由字母,數(shù)字,下劃線組成,但首字母不能是數(shù)字或下劃線,另外不能是關(guān)鍵詞 keyword 比如 class, for, return, global, pass, 或 raise 。

如果 rename 為真, 無效字段名會(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)值域必須跟其他沒有默認(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í)例沒有字典,所以它們要更輕量,并且占用更小內(nèi)存。

要支持封存操作,應(yīng)當(dāng)將命名元組類賦值給一個(gè)匹配 typename 的變量。

在 3.1 版更改: 添加了對(duì) rename 的支持。

在 3.6 版更改: verboserename 參數(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è)屬性。為了防止字段名沖突,方法和屬性以下劃線開始。

classmethod somenamedtuple._make(iterable)?

類方法從存在的序列或迭代實(shí)例創(chuàng)建一個(gè)新實(shí)例。

>>>
>>> t = [11, 22]
>>> Point._make(t)
Point(x=11, y=22)
somenamedtuple._asdict()?

返回一個(gè)新的 dict ,它將字段名稱映射到它們對(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)換為需要的類型: 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è)新的命名元組類型。

>>>
>>> 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?

字典將字段名稱映射到默認(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類,它可以很容易的通過子類更改功能。這里是如何添加一個(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

上面的子類設(shè)置 __slots__ 為一個(gè)空元組。通過阻止創(chuàng)建實(shí)例字典保持了較低的內(nèi)存開銷。

子類化對(duì)于添加和存儲(chǔ)新的名字域是無效的。應(yīng)當(dāng)通過 _fields 創(chuàng)建一個(gè)新的命名元組來實(shí)現(xiàn)它:

>>>
>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))

文檔字符串可以自定義,通過直接賦值給 __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 版更改: 文檔字符串屬性變成可寫。

參見

  • 請(qǐng)參閱 typing.NamedTuple ,以獲取為命名元組添加類型提示的方法。 它還使用 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)將生成的特殊方法添加到用戶定義的類中。

OrderedDict 對(duì)象?

有序詞典就像常規(guī)詞典一樣,但有一些與排序操作相關(guān)的額外功能。由于內(nèi)置的 dict 類獲得了記住插入順序的能力(在 Python 3.7 中保證了這種新行為),它們變得不那么重要了。

一些與 dict 的不同仍然存在:

  • 常規(guī)的 dict 被設(shè)計(jì)為非常擅長(zhǎng)映射操作。 跟蹤插入順序是次要的。

  • OrderedDict 旨在擅長(zhǎng)重新排序操作。 空間效率、迭代速度和更新操作的性能是次要的。

  • The OrderedDict algorithm can handle frequent reordering operations better than dict. 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 with p == q and all(k1 == k2 for k1, k2 in zip(p, q)).

  • OrderedDict 類的 popitem() 方法有不同的簽名。它接受一個(gè)可選參數(shù)來指定彈出哪個(gè)元素。

    A regular dict can emulate OrderedDict's od.popitem(last=True) with d.popitem() which is guaranteed to pop the rightmost (last) item.

    A regular dict can emulate OrderedDict's od.popitem(last=False) with (k := next(iter(d)), d.pop(k)) which will return and remove the leftmost (first) item if it exists.

  • OrderedDict 類有一個(gè) move_to_end() 方法,可以有效地將元素移動(dòng)到任一端。

    A regular dict can emulate OrderedDict's od.move_to_end(k, last=True) with d[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's od.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 子類的實(shí)例,它具有專門用于重新排列字典順序的方法。

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ì)于通常的映射方法,有序字典還另外提供了逆序迭代的支持,通過 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)在支持逆序迭代,通過 reversed()

在 3.6 版更改: PEP 468 贊成將關(guān)鍵詞參數(shù)的順序保留, 通過傳遞給 OrderedDict 構(gòu)造器和它的 update() 方法。

在 3.9 版更改: 增加了合并 (|) 與更新 (|=) 運(yùn)算符,相關(guā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 類是用作字典對(duì)象的外包裝。對(duì)這個(gè)類的需求已部分由直接創(chuàng)建 dict 的子類的功能所替代;不過,這個(gè)類處理起來更容易,因?yàn)榈讓拥淖值淇梢宰鳛閷傩詠碓L問。

class collections.UserDict([initialdata])?

模擬字典的類。 這個(gè)實(shí)例的內(nèi)容保存在一個(gè)常規(guī)字典中,它可以通過 UserDict 實(shí)例的 data 屬性來訪問。 如果提供了 initialdata,則 data 會(huì)用其內(nèi)容來初始化;請(qǐng)注意對(duì) initialdata 的引用將不會(huì)被保留,以允許它被用于其他目的。

UserDict 實(shí)例提供了以下屬性作為擴(kuò)展方法和操作的支持:

data?

一個(gè)真實(shí)的字典,用于保存 UserDict 類的內(nèi)容。

UserList 對(duì)象?

這個(gè)類封裝了列表對(duì)象。它是一個(gè)有用的基礎(chǔ)類,對(duì)于你想自定義的類似列表的類,可以繼承和覆蓋現(xiàn)有的方法,也可以添加新的方法。這樣我們可以對(duì)列表添加新的行為。

對(duì)這個(gè)類的需求已部分由直接創(chuàng)建 list 的子類的功能所替代;不過,這個(gè)類處理起來更容易,因?yàn)榈讓拥牧斜砜梢宰鳛閷傩詠碓L問。

class collections.UserList([list])?

模擬一個(gè)列表。這個(gè)實(shí)例的內(nèi)容被保存為一個(gè)正常列表,通過 UserListdata 屬性存取。實(shí)例內(nèi)容被初始化為一個(gè) list 的copy,默認(rèn)為 [] 空列表。 list 可以是迭代對(duì)象,比如一個(gè)Python列表,或者一個(gè) UserList 對(duì)象。

UserList 提供了以下屬性作為可變序列的方法和操作的擴(kuò)展:

data?

一個(gè) list 對(duì)象用于存儲(chǔ) UserList 的內(nèi)容。

子類化的要求: UserList 的子類需要提供一個(gè)構(gòu)造器,可以無參數(shù)調(diào)用,或者一個(gè)參數(shù)調(diào)用。返回一個(gè)新序列的列表操作需要?jiǎng)?chuàng)建一個(gè)實(shí)現(xiàn)類的實(shí)例。它假定了構(gòu)造器可以以一個(gè)參數(shù)進(jìn)行調(diào)用,這個(gè)參數(shù)是一個(gè)序列對(duì)象,作為數(shù)據(jù)源。

如果一個(gè)分離的類不希望依照這個(gè)需求,所有的特殊方法就必須重寫;請(qǐng)參照源代碼進(jìn)行修改。

UserString 對(duì)象?

UserString 類是用作字符串對(duì)象的外包裝。對(duì)這個(gè)類的需求已部分由直接創(chuàng)建 str 的子類的功能所替代;不過,這個(gè)類處理起來更容易,因?yàn)榈讓拥淖址梢宰鳛閷傩詠碓L問。

class collections.UserString(seq)?

模擬一個(gè)字符串對(duì)象。這個(gè)實(shí)例對(duì)象的內(nèi)容保存為一個(gè)正常字符串,通過 UserStringdata 屬性存取。實(shí)例內(nèi)容初始化設(shè)置為 seq 的copy。seq 參數(shù)可以是任何可通過內(nèi)建 str() 函數(shù)轉(zhuǎn)換為字符串的對(duì)象。

UserString 提供了以下屬性作為字符串方法和操作的額外支持:

data?

一個(gè)真正的 str 對(duì)象用來存放 UserString 類的內(nèi)容。

在 3.5 版更改: 新方法 __getnewargs__, __rmod__, casefold, format_map, isprintable, 和 maketrans。