collections --- 容器數據類(lèi)型?

Source code: Lib/collections/__init__.py


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

namedtuple()

創(chuàng )建命名元組子類(lèi)的工廠(chǎng)函數

deque

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

ChainMap

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

Counter

字典的子類(lèi),提供了可哈希對象的計數功能

OrderedDict

字典的子類(lèi),保存了他們被添加的順序

defaultdict

字典的子類(lèi),提供了一個(gè)工廠(chǎng)函數,為字典查詢(xún)提供一個(gè)默認值

UserDict

封裝了字典對象,簡(jiǎn)化了字典子類(lèi)化

UserList

封裝了列表對象,簡(jiǎn)化了列表子類(lèi)化

UserString

封裝了字符串對象,簡(jiǎn)化了字符串子類(lèi)化

ChainMap 對象?

3.3 新版功能.

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

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

class collections.ChainMap(*maps)?

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

底層映射被存儲在一個(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è)列表是按照第一次搜索到最后一次搜索的順序組織的。它是僅有的存儲狀態(tài),可以被修改。列表最少包含一個(gè)映射。

new_child(m=None, **kwargs)?

返回一個(gè)新的 ChainMap,其中包含一個(gè)新的映射,后面跟隨當前實(shí)例中的所有映射。 如果指定了 m,它會(huì )成為新的映射加在映射列表的前面;如果未指定,則會(huì )使用一個(gè)空字典,因此調用 d.new_child() 就等價(jià)于 ChainMap({}, *d.maps)。 如果指定了任何關(guān)鍵字參數,它們會(huì )更新所傳入的映射或新的空字典。 此方法被用于創(chuàng )建子上下文,它可在不改變任何上級映射的情況下被更新。

在 3.4 版更改: 添加了 m 可選參數。

在 3.10 版更改: 增加了對關(guān)鍵字參數的支持。

parents?

屬性返回一個(gè)新的 ChainMap 包含所有的當前實(shí)例的映射,除了第一個(gè)。這樣可以在搜索的時(shí)候跳過(guò)第一個(gè)映射。 使用的場(chǎng)景類(lèi)似在 nested scopes 嵌套作用域中使用 nonlocal 關(guān)鍵詞。用例也可以類(lèi)比內建函數 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() 調用序列相同的順序,從最后一個(gè)映射開(kāi)始:

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

在 3.9 版更改: 增加了對 ||= 運算符的支持,相關(guān)說(shuō)明見(jiàn) PEP 584。

參見(jiàn)

ChainMap 例子和方法?

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

模擬Python內部lookup鏈的例子

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

讓用戶(hù)指定的命令行參數優(yōu)先于環(huán)境變量,優(yōu)先于默認值的例子

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í)現它

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

一個(gè)計數器工具提供快速和方便的計數。比如

>>>
>>> # 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),用于計數可哈希對象。它是一個(gè)集合,元素像字典鍵(key)一樣存儲,它們的計數存儲為值。計數可以是任何整數值,包括0和負數。 Counter 類(lèi)有點(diǎn)像其他語(yǔ)言中的 bags或multisets。

元素從一個(gè) iterable 被計數或從其他的 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對象有一個(gè)字典接口,如果引用的鍵沒(méi)有任何記錄,就返回一個(gè)0,而不是彈出一個(gè) KeyError :

>>>
>>> c = Counter(['eggs', 'ham'])
>>> c['bacon']                              # count of a missing element is zero
0

設置一個(gè)計數為0不會(huì )從計數器中移去一個(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è)元素將重復出現計數值所指定次。 元素會(huì )按首次出現的順序返回。 如果一個(gè)元素的計數值小于一,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)的元素及出現次數,按常見(jiàn)程度由高到低排序。 如果 n 被省略或為 None,most_common() 將返回計數器中的 所有 元素。 計數值相等的元素按首次出現的順序排序:

>>>
>>> Counter('abracadabra').most_common(3)
[('a', 5), ('b', 2), ('r', 2)]
subtract([iterable-or-mapping])?

迭代對象映射對象 減去元素。像 dict.update() 但是是減去,而不是替換。輸入和輸出都可以是0或者負數。

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

計算總計數值。

>>>
>>> c = Counter(a=10, b=5, c=0)
>>> c.total()
15

3.10 新版功能.

通常字典方法都可用于 Counter 對象,除了有兩個(gè)方法工作方式與字典并不相同。

fromkeys(iterable)?

這個(gè)類(lèi)方法沒(méi)有在 Counter 中實(shí)現。

update([iterable-or-mapping])?

迭代對象 計數元素或者 從另一個(gè) 映射對象 (或計數器) 添加。 像 dict.update() 但是是加上,而不是替換。另外,迭代對象 應該是序列元素,而不是一個(gè) (key, value) 對。

計數對象支持相等性、子集和超集關(guān)系等富比較運算符: ==, !=, <, <=, >, >=。 所有這些檢測會(huì )將不存在的元素當作計數值為零,因此 Counter(a=1) == Counter(a=1, b=0) 將返回真值。

3.10 新版功能: Rich comparison operations were added.

在 3.10 版更改: 在相等性檢測中,不存在的元素會(huì )被當作計數值為零。 在此之前,Counter(a=3)Counter(a=3, b=0) 會(huì )被視為不同。

Counter 對象的常用案例

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

單目加和減(一元操作符)意思是從空計數器加或者減去。

>>>
>>> c = Counter(a=2, b=-4)
>>> +c
Counter({'a': 2})
>>> -c
Counter({'b': 4})

3.3 新版功能: 添加了對一元加,一元減和位置集合操作的支持。

備注

計數器主要是為了表達運行的正的計數而設計;但是,小心不要預先排除負數或者其他類(lèi)型。為了幫助這些用例,這一節記錄了最小范圍和類(lèi)型限制。

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

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

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

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

  • elements() 方法要求正整數計數。忽略0和負數計數。

參見(jiàn)

  • Bag class 在 Smalltalk。

  • Wikipedia 鏈接 Multisets.

  • C++ multisets 教程和例子。

  • 數學(xué)操作和多集合用例,參考 Knuth, Donald. The Art of Computer Programming Volume II, Section 4.6.3, Exercise 19 。

  • 在給定數量和集合元素枚舉所有不同的多集合,參考 itertools.combinations_with_replacement()

    map(Counter, combinations_with_replacement('ABC', 2)) # --> AA AB AC BB BC CC
    

deque 對象?

class collections.deque([iterable[, maxlen]])?

返回一個(gè)新的雙向隊列對象,從左到右初始化(用方法 append()) ,從 iterable (迭代對象) 數據創(chuàng )建。如果 iterable 沒(méi)有指定,新隊列為空。

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

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

如果 maxlen 沒(méi)有指定或者是 None ,deques 可以增長(cháng)到任意長(cháng)度。否則,deque就限定到指定最大長(cháng)度。一旦限定長(cháng)度的deque滿(mǎn)了,當新項加入時(shí),同樣數量的項就從另一端彈出。限定長(cháng)度deque提供類(lèi)似Unix filter tail 的功能。它們同樣可以用與追蹤最近的交換和其他數據池活動(dòng)。

雙向隊列(deque)對象支持以下方法:

append(x)?

添加 x 到右端。

appendleft(x)?

添加 x 到左端。

clear()?

移除所有元素,使其長(cháng)度為0.

copy()?

創(chuàng )建一份淺拷貝。

3.5 新版功能.

count(x)?

計算 deque 中元素等于 x 的個(gè)數。

3.2 新版功能.

extend(iterable)?

擴展deque的右側,通過(guò)添加iterable參數中的元素。

extendleft(iterable)?

擴展deque的左側,通過(guò)添加iterable參數中的元素。注意,左添加時(shí),在結果中iterable參數中的順序將被反過(guò)來(lái)添加。

index(x[, start[, stop]])?

返回 x 在 deque 中的位置(在索引 start 之后,索引 stop 之前)。 返回第一個(gè)匹配項,如果未找到則引發(fā) ValueError。

3.5 新版功能.

insert(i, x)?

在位置 i 插入 x 。

如果插入會(huì )導致一個(gè)限長(cháng) deque 超出長(cháng)度 maxlen 的話(huà),就引發(fā)一個(gè) IndexError。

3.5 新版功能.

pop()?

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

popleft()?

移去并且返回一個(gè)元素,deque 最左側的那一個(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 是負數,就向左循環(huán)。

如果deque不是空的,向右循環(huán)移動(dòng)一步就等價(jià)于 d.appendleft(d.pop()) , 向左循環(huán)一步就等價(jià)于 d.append(d.popleft()) 。

Deque對象同樣提供了一個(gè)只讀屬性:

maxlen?

Deque的最大尺寸,如果沒(méi)有限定的話(huà)就是 None 。

3.1 新版功能.

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

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

這一節展示了deque的多種用法。

限長(chá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è)用法是維護一個(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)調度器 可以通過(guò)在 deque 中放入迭代器來(lái)實(shí)現。值從當前迭代器的位置0被取出并暫存(yield)。 如果這個(gè)迭代器消耗完畢,就用 popleft() 將其從對列中移去;否則,就通過(guò) rotate() 將它移到隊列的末尾

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í)現 deque 切片和刪除。 例如, 一個(gè)純的Python del d[n] 實(shí)現依賴(lài)于 rotate() 來(lái)定位要彈出的元素

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

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

defaultdict 對象?

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

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

本對象包含一個(gè)名為 default_factory 的屬性,構造時(shí),第一個(gè)參數用于為該屬性提供初始值,默認為 None。所有其他參數(包括關(guān)鍵字參數)都相當于傳遞給 dict 的構造函數。

defaultdict 對象除了支持標準 dict 的操作,還支持以下方法作為擴展:

__missing__(key)?

如果 default_factory 屬性為 None,則調用本方法會(huì )拋出 KeyError 異常,附帶參數 key。

如果 default_factory 不為 None,則它會(huì )被(不帶參數地)調用來(lái)為 key 提供一個(gè)默認值,這個(gè)值和 key 作為一對鍵值對被插入到字典中,并作為本方法的返回值返回。

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

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

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

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

default_factory?

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

在 3.9 版更改: 增加了合并 (|) 與更新 (|=) 運算符,相關(guān)說(shuō)明見(jiàn) PEP 584。

defaultdict 例子?

使用 list 作為 default_factory,很輕松地將(鍵-值對組成的)序列轉換為(鍵-列表組成的)字典:

>>>
>>> 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])]

當每個(gè)鍵第一次遇見(jiàn)時(shí),它還沒(méi)有在字典里面,所以自動(dòng)創(chuàng )建該條目,即調用 default_factory 方法,返回一個(gè)空的 list。 list.append() 操作添加值到這個(gè)新的列表里。當再次存取該鍵時(shí),就正常操作,list.append() 添加另一個(gè)值到列表中。這個(gè)計數比它的等價(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])]

設置 default_factoryint,使 defaultdict 用于計數(類(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)]

當一個(gè)字母首次遇到時(shí),它會(huì )查詢(xún)失敗,則 default_factory 會(huì )調用 int() 來(lái)提供一個(gè)整數 0 作為默認值。后續的自增操作建立起對每個(gè)字母的計數。

函數 int() 總是返回 0,這是常數函數的特殊情況。一個(gè)更快和靈活的方法是使用 lambda 函數,可以提供任何常量值(不只是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>'

設置 default_factoryset 使 defaultdict 用于構建 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() 命名元組的工廠(chǎng)函數?

命名元組賦予每個(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)元組的對象,可以通過(guò)字段名來(lái)獲取屬性值,同樣也可以通過(guò)索引和迭代獲取值。子類(lèi)實(shí)例同樣有文檔字符串(類(lèi)名和字段名)另外一個(gè)有用的 __repr__() 方法,以 name=value 格式列明了元組內容。

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

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

如果 rename 為真, 無(wú)效字段名會(huì )自動(dòng)轉換成位置名。比如 ['abc', 'def', 'ghi', 'abc'] 轉換成 ['abc', '_1', 'ghi', '_3'] , 消除關(guān)鍵詞 def 和重復字段名 abc 。

defaults 可以為 None 或者是一個(gè)默認值的 iterable 。如果一個(gè)默認值域必須跟其他沒(méi)有默認值的域在一起出現,defaults 就應用到最右邊的參數。比如如果域名 ['x', 'y', 'z'] 和默認值 (1, 2) ,那么 x 就必須指定一個(gè)參數值 ,y 默認值 1 , z 默認值 2 。

如果 module 值有定義,命名元組的 __module__ 屬性值就被設置。

命名元組實(shí)例沒(méi)有字典,所以它們要更輕量,并且占用更小內存。

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

在 3.1 版更改: 添加了對 rename 的支持。

在 3.6 版更改: verboserename 參數成為 僅限關(guān)鍵字參數.

在 3.6 版更改: 添加了 module 參數。

在 3.7 版更改: 移除了 verbose 形參和 _source 屬性。

在 3.7 版更改: 添加了 defaults 參數和 _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)映射到它們對應的值:

>>>
>>> p = Point(x=11, y=22)
>>> p._asdict()
{'x': 11, 'y': 22}

在 3.1 版更改: 返回一個(gè) OrderedDict 而不是 dict 。

在 3.8 版更改: 返回一個(gè)常規 dict 而不是 OrderedDict。 因為自 Python 3.7 起,常規字典已經(jīng)保證有序。 如果需要 OrderedDict 的額外特性,推薦的解決方案是將結果轉換為需要的類(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?

字符串元組列出了字段名。用于提醒和從現有元組創(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)映射到默認值。

>>>
>>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0])
>>> Account._field_defaults
{'balance': 0}
>>> Account('premium')
Account(type='premium', balance=0)

要獲取這個(gè)名字域的值,使用 getattr() 函數 :

>>>
>>> getattr(p, 'x')
11

轉換一個(gè)字典到命名元組,使用 ** 兩星操作符 (所述如 解包實(shí)參列表):

>>>
>>> d = {'x': 11, 'y': 22}
>>> Point(**d)
Point(x=11, y=22)

因為一個(gè)命名元組是一個(gè)正常的Python類(lèi),它可以很容易的通過(guò)子類(lèi)更改功能。這里是如何添加一個(gè)計算域和定寬輸出打印格式:

>>>
>>> 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)設置 __slots__ 為一個(gè)空元組。通過(guò)阻止創(chuàng )建實(shí)例字典保持了較低的內存開(kāi)銷(xiāo)。

子類(lèi)化對于添加和存儲新的名字域是無(wú)效的。應當通過(guò) _fields 創(chuàng )建一個(gè)新的命名元組來(lái)實(shí)現它:

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

  • 請參閱 typing.NamedTuple ,以獲取為命名元組添加類(lèi)型提示的方法。 它還使用 class 關(guān)鍵字提供了一種優(yōu)雅的符號:

    class Component(NamedTuple):
        part_number: int
        weight: float
        description: Optional[str] = None
    
  • 對于以字典為底層的可變域名, 參考 types.SimpleNamespace() 。

  • dataclasses 模塊提供了一個(gè)裝飾器和一些函數,用于自動(dòng)將生成的特殊方法添加到用戶(hù)定義的類(lèi)中。

OrderedDict 對象?

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

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

  • 常規的 dict 被設計為非常擅長(cháng)映射操作。 跟蹤插入順序是次要的。

  • OrderedDict 旨在擅長(chá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.

  • 對于 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 類(lèi)的 popitem() 方法有不同的簽名。它接受一個(gè)可選參數來(lái)指定彈出哪個(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 類(lèi)有一個(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 子類(lèi)的實(shí)例,它具有專(zhuān)門(mén)用于重新排列字典順序的方法。

3.1 新版功能.

popitem(last=True)?

有序字典的 popitem() 方法移除并返回一個(gè) (key, value) 鍵值對。 如果 last 值為真,則按 LIFO 后進(jìn)先出的順序返回鍵值對,否則就按 FIFO 先進(jìn)先出的順序返回鍵值對。

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 新版功能.

相對于通常的映射方法,有序字典還另外提供了逆序迭代的支持,通過(guò) reversed() 。

OrderedDict 之間的相等測試是順序敏感的,實(shí)現為 list(od1.items())==list(od2.items()) 。 OrderedDict 對象和其他的 Mapping 的相等測試,是順序敏感的字典測試。這允許 OrderedDict 替換為任何字典可以使用的場(chǎng)所。

在 3.5 版更改: OrderedDict 的項(item),鍵(key)和值(value) 視圖 現在支持逆序迭代,通過(guò) reversed() 。

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

在 3.9 版更改: 增加了合并 (|) 與更新 (|=) 運算符,相關(guān)說(shuō)明見(jiàn) PEP 584。

OrderedDict 例子和用法?

創(chuàng )建記住鍵值 最后 插入順序的有序字典變體很簡(jiǎ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 對于實(shí)現 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 對象?

UserDict 類(lèi)是用作字典對象的外包裝。對這個(gè)類(lèi)的需求已部分由直接創(chuàng )建 dict 的子類(lèi)的功能所替代;不過(guò),這個(gè)類(lèi)處理起來(lái)更容易,因為底層的字典可以作為屬性來(lái)訪(fǎng)問(wèn)。

class collections.UserDict([initialdata])?

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

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

data?

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

UserList 對象?

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

對這個(gè)類(lèi)的需求已部分由直接創(chuàng )建 list 的子類(lèi)的功能所替代;不過(guò),這個(gè)類(lèi)處理起來(lái)更容易,因為底層的列表可以作為屬性來(lái)訪(fǎng)問(wèn)。

class collections.UserList([list])?

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

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

data?

一個(gè) list 對象用于存儲 UserList 的內容。

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

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

UserString 對象?

UserString 類(lèi)是用作字符串對象的外包裝。對這個(gè)類(lèi)的需求已部分由直接創(chuàng )建 str 的子類(lèi)的功能所替代;不過(guò),這個(gè)類(lèi)處理起來(lái)更容易,因為底層的字符串可以作為屬性來(lái)訪(fǎng)問(wèn)。

class collections.UserString(seq)?

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

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

data?

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

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