8.3. collections高性能容器数据类型

在 2.4 版本新。

源程序代码:Lib/collections.pyLib/_abcoll.py


这个模块实现了 Python 的通用内置容器、字典列表集合,和元组专门的容器数据类型提供替代品。

namedtuple() factory function for creating tuple subclasses with named fields

在 2.6 版本新。

deque list-like container with fast appends and pops on either end

在 2.4 版本新。

Counter dict subclass for counting hashable objects

在 2.7 版本新。

OrderedDict dict subclass that remembers the order entries were added

在 2.7 版本新。

defaultdict dict subclass that calls a factory function to supply missing values

新版本 2.5 中的。

除了具体的容器类,collections模块提供抽象基类,这些类,可以用来测试是否一个类提供特定的接口,例如,它是否是 hashable 或映射。

8.3.1. Counter 对象

计数器工具用来提供方便快捷的计数支持。举个例子:

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

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

计数器dict子类的计数 hashable 对象。它是一个无序的集合,其中他们计数存储作为字典值和元素存储为字典键。计数允许为任何整数值,包括零或负计数。计数器类是类似于袋或在其他语言中的多重集。

元素从计数可迭代或从另一个映射(或计数器) 进行初始化:

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

计数器对象有字典接口除外,他们返回为丢失的项目,而不是引发KeyError计数为零:

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

设置计数为零并不会从计数器中删除一个元素。使用del以将它完全移除:

>>> c['sausage'] = 0                        # counter entry with a zero count
>>> del c['sausage']                        # del actually removes the entry

在 2.7 版本新。

计数器对象支持所有词典超越那些可用的三种方法:

elements()

返回重复其计数的许多倍的每个元素的迭代器。按任意顺序返回元素。如果元素数小于 1, elements()将会忽略它。

>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> list(c.elements())
['a', 'a', 'a', 'a', 'b', 'b']
most_common([n])

返回列表n最常见元素及从其计数最常见到最低限度。如果未指定n ,则most_common()将返回计数器中的所有元素。具有同等数量的元素是任意排序:

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

元素减去可迭代或从另一个映射(或计数器)。dict.update()但减去计数而不是取代他们。输入和输出可能为零或负。

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

通常的字典方法也可作用于计数器对象,除了两者的用法不同。

fromkeys(iterable)

此方法不适用于计数器对象。使用会引发NotImplementedError。

update([iterable-or-mapping])

元素从计数可迭代或在补充说: 从另一个映射(或计数器)。dict.update()但添加计数而不是取代他们。此外,可迭代预计将是一个序列的元素,不是一个序列的(键, 值)对。

使用计数器对象的常见形式:

sum(c.values())                 # 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 += Counter()                  # remove zero and negative counts

几个数学运算可供结合计数器对象产生多重 (计数大于零的计数器)。加法和减法结合计数器通过添加或减去对应元素的计数。交集和并集返回最小值和最大值对应的数目。每个操作可以接受输入的符号的计数,但输出将排除结果与计数为零或更少。

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

计数器的设计主要是用正整数来表示运行计数 ;然而,小心被不必要地妨碍用例需要其他类型或负值。来帮助那些使用案例,这部分文档的最小的范围和类型的限制。

  • The Counter class itself is a dictionary subclass with no restrictions on its keys and values. The values are intended to be numbers representing counts, but you could store anything in the value field.
  • The most_common() method requires only that the values be orderable.
  • For in-place operations such as c[key] += 1, the value type need only support addition and subtraction. So fractions, floats, and decimals would work and negative values are supported. The same is also true for update() and subtract() which allow negative and zero values for both inputs and outputs.
  • The multiset methods are designed only for use cases with positive values. The inputs may be negative or zero, but only outputs with positive values are created. There are no type restrictions, but the value type needs to support addition, subtraction, and comparison.
  • The elements() method requires integer counts. It ignores zero and negative counts.

请参见

  • 对于 Python 2.5 和早期包括的方法适合使用 Python 2.4 的计数器类

  • Smalltalk 的袋类

  • 多重集的维基百科条目。

  • C + + 多重集教程的例子。

  • 多重集和他们用例的数学运算,请参阅Knuth,唐纳德。艺术的计算机编程第二卷,第节 4.6.3,行使 19。

  • 若要枚举一组给定的元素的所有不同多重的给定大小,请参阅itertools.combinations_with_replacement()

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

8.3.2. deque 对象

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

返回一个新的 deque 对象初始化左到右 (使用append ()) 中的数据可迭代如果可迭代未指定,则新的 deque 是空的。

deque是一个通用的堆栈和队列 (名称发音"deck",是"双端队列"的简称)。deques支持线程安全,能够有效的利用内存。无论从队列的哪段入队和出队,性能都能够接近于O(1)。

列表对象支持类似的行动,但只是优化了固定长度操作的速度。像pop(0)insert(0, v)这样改变列表长度和元素展示位置的操作都会带来 O(n)的内存移动消耗。

2.4 版本中更新的内容

如果不指定maxlen或者为None,deques可以长到任意长度。否则,deque 为界到指定的最大长度。一旦有界的 deque 满了,再添加新项目时,就会有相应数量的项目将从另一端被丢弃。有界队列提供了类似于 Unix 中的tail命令的功能。他们还可用于跟踪交易记录和其他池的数据感兴趣的只是最新的活动在哪里。

2.6 版本中的更改:添加的maxlen参数。

Deque 对象支持下列方法:

append(x)

x添加到 deque 的右侧。

appendleft(x)

x添加到 deque 的左侧。

clear()

从留下长度为 0 的 deque 中移除所有元素。

count(x)

统计 deque 中值为x的个数。

在 2.7 版本新。

extend(iterable)

通过追加元素从可迭代参数扩展的 deque 的右侧。

extendleft(iterable)

通过将附加元素从扩展 deque 的左侧可迭代请注意,左边的一系列附加结果在扭转可迭代参数中元素的顺序。

pop()

删除并从右侧的双端队列中返回的元素。如果没有元素存在,提出了IndexError

popleft()

移除并返回一个元素从 deque 的左侧。如果没有元素存在,提出了IndexError

remove(value)

删除的第一个匹配项。如果未找到,引发ValueError

新版本 2.5 中的。

reverse()

翻转 deque 的元素,然后返回None

在 2.7 版本新。

rotate(n)

deque中的元素向右移动n个位置。如果n是负数的向左移动。向右移动一步相当于: d.appendleft(d.pop())

Deque 对象还提供了一个只读属性:

maxlen

Deque 的最大长度。如果没有边界,则返回None

在 2.7 版本新。

除了以上所述,通过支持迭代、 pickling、 len(d)reversed(d)copy.copy(d)copy.deepcopy(d)、 检查成员用in运算符,和下标索引d [-1]索引的访问两端都是 o (1),但在中间部分速度就减慢到 o (n)。对于快速的随机访问,改用列表。

示例:

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

8.3.2.1. deque Recipes

本节将展示双端队列的各种处理方法

有界的长度通过提供类似于 Unix 中的尾巴筛选器的功能:

def tail(filename, n=10):
    'Return the last n lines of a file'
    return deque(open(filename), n)

使用通过另一种方法是通过追加向右和向左跳跳保持的最近添加的元素的序列:

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 / float(n)

Rotate()方法提供了一种实现deque切片和删除方法。例如, del d [n]的一个纯 Python 实现依赖于rotate()方法来定位要弹出的元素:

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

若要实现deque切片,请使用类似的方法,应用rotate() ,使目标元素 deque 的左侧。删除旧的条目,与popleft()、 添加新条目与extend(),然后反转。以较小的变异上的方法,很容易实现创新风格堆栈操作 (例如, dupdropswapoverpickrot,和roll

8.3.3. defaultdict objects

class collections.defaultdict([default_factory[, ...]])

返回一个新的类似于字典对象。 defaultdict是内置字典类的子类。它将重写一个方法,并添加一个可写的实例变量。其余的功能字典类相同,未在此处。

第一个参数提供的初始值为default_factory属性 ;它将默认为None所有其余的参数是相同的处理,就像他们被传递到字典构造函数包括关键字参数。

新版本 2.5 中的。

defaultdict对象支持的以下方法除了标准字典操作:

__missing__(key)

如果default_factory属性是None,这引发KeyError异常与密钥作为参数。

如果default_factory不是None,它被称为参数提供一个默认值,对于给定的密钥的情况下,对于关键,字典中插入此值并将其返回。

如果调用default_factory引发异常此异常将被传播不变。

字典类的__getitem__()方法被调用此方法,当未找到所请求的键 ;无论它返回引发然后返回或提出的__getitem__()

请注意, __missing__() 呼吁除__getitem__()以外的任何操作。这意味着, get ()会像正常的字典,返回作为默认值,而不是使用default_factory

defaultdict对象支持以下实例变量:

default_factory

此属性使用__missing__()方法 ;它初始化从第一个参数为构造函数中,如果存在的话,或为没有,如果缺席。

8.3.3.1. defaultdict Examples

作为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)
...
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

当第一次遇到的每个键时,它已不在映射中 ;所以这是自动创建一个条目使用default_factory函数,返回一个空列表然后, list.append()操作附加到新的列表的值。当再次遇到了键,则查找收益通常 (返回该注册表项的列表中) 和list.append()操作将另一个值添加到列表中。这种技术是使用dict.setdefault()等效技术较简单和迅速:

>>> d = {}
>>> for k, v in s:
...     d.setdefault(k, []).append(v)
...
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

default_factory设置为int使得defaultdict对于计数 (如袋或在其他语言中的多重集) 非常有用:

>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
...     d[k] += 1
...
>>> d.items()
[('i', 4), ('p', 2), ('s', 4), ('m', 1)]

当第一次遇到一封信时,这是缺少从映射,所以default_factory函数调用int ()来提供默认计数为零。然后,增量操作建立的计数每一封信。

它始终返回零函数int ()是常量函数的只是一个特殊的情况。更快、 更灵活的方式来创建常量函数是使用itertools.repeat()可以供应任何常量值 (不只是零):

>>> def constant_factory(value):
...     return itertools.repeat(value).next
>>> d = defaultdict(constant_factory('<missing>'))
>>> d.update(name='John', action='ran')
>>> '%(name)s %(action)s to %(object)s' % d
'John ran to <missing>'

default_factory设置为设置使得defaultdict用于建立一个字典集:

>>> 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)
...
>>> d.items()
[('blue', set([2, 4])), ('red', set([1, 3]))]

8.3.4. namedtuple()

命名的元组分配给每个元组中的位置的意思,并允许更具可读性,自记录代码。他们可以无论使用常规的元组,并且他们将添加能够访问字段用于按名称而不是位置索引。

collections.namedtuple(typename, field_names[, verbose=False][, rename=False])

返回以typename为名的新的元组子类。新的子类用于创建类似元祖的对象,这些对象拥有可通过调用属性来访问的字段,并且可以索引和迭代。子类的实例也有一个有用的文档字符串 (与 typename 和 field_names) 和有用的__repr__()方法,列出中的元组内容名称 = 值格式。

Field_names是一个字符串序列,如['x' 'y']或者, field_names可以是单个字符串与例如由空格或逗号分隔每个字段名'x y'' x, y'

任何有效的 Python 标识符可用于 fieldname 除了以下划线开头的名称。有效的标识符由字母、 数字和下划线组成,但做不能以数字或下划线开头,不能关键字例如返回全球传递打印提高

如果rename为true,无效的字段名会自动替换为位置的名称。例如, ['abc' 'def' 'ghi' 'abc']转换为['abc' '_1' 'ghi' '_3'],消除关键字def和重复使用字段名abc

如果详细属实,建成以前只被打印类定义。

名为元组实例并没有每个实例字典,所以他们是轻量级和要求没有更多的内存比常规的元组。

在 2.6 版本新。

2.7 版本中的更改:添加支持重命名

示例:

>>> Point = namedtuple('Point', ['x', 'y'], verbose=True)
class Point(tuple):
    'Point(x, y)'

    __slots__ = ()

    _fields = ('x', 'y')

    def __new__(_cls, x, y):
        'Create a new instance of Point(x, y)'
        return _tuple.__new__(_cls, (x, y))

    @classmethod
    def _make(cls, iterable, new=tuple.__new__, len=len):
        'Make a new Point object from a sequence or iterable'
        result = new(cls, iterable)
        if len(result) != 2:
            raise TypeError('Expected 2 arguments, got %d' % len(result))
        return result

    def __repr__(self):
        'Return a nicely formatted representation string'
        return 'Point(x=%r, y=%r)' % self

    def _asdict(self):
        'Return a new OrderedDict which maps field names to their values'
        return OrderedDict(zip(self._fields, self))

    def _replace(_self, **kwds):
        'Return a new Point object replacing specified fields with new values'
        result = _self._make(map(kwds.pop, ('x', 'y'), _self))
        if kwds:
            raise ValueError('Got unexpected field names: %r' % kwds.keys())
        return result

    def __getnewargs__(self):
        'Return self as a plain tuple.   Used by copy and pickle.'
        return tuple(self)

    __dict__ = _property(_asdict)

    def __getstate__(self):
        'Exclude the OrderedDict from pickling'
        pass

    x = _property(_itemgetter(0), doc='Alias for field number 0')

    y = _property(_itemgetter(1), doc='Alias for field number 1')


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

命名的元组是将字段名称分配给由csvsqlite3模块返回的结果元组尤其有用:

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

从元组继承的方法,除了命名的元组支持三个额外的方法和一个属性。为防止冲突与字段名称,方法和属性的名称以下划线开头。

classmethod somenamedtuple._make(iterable)

使新的实例,从现有的序列或可迭代的类方法。

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

返回新的OrderedDict字段名称映射到其相应的值:

>>> p._asdict()
OrderedDict([('x', 11), ('y', 22)])

2.7 版本中的更改:返回OrderedDict而不是常规的字典

somenamedtuple._replace(kwargs)

返回指定的字段替换为新值的命名的元组的一个新实例:

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

元组的列表的字段名称的字符串。可用于反思和创建新的命名的元组类型从现有的已命名的元组。

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

若要检索其名称存储在一个字符串中的一个字段,请使用getattr()函数:

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

若要将一本字典转换为一个命名的元组,使用双-星级-运算符 (如开箱的参数列表中所述):

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

因为命名的元组是一个常规的 Python 类,很容易添加或更改它的子类的功能。下面介绍了如何添加一个计算的字段和固定宽度打印格式:

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

如上所示的子类将__slots__设置为一个空的元组。这有助于防止创建的实例字典通过保持内存需求低。

子类化不是新的存储字段中添加有用的。相反,只需创建一个新的命名的元组类型从_fields属性:

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

默认值可以通过使用_replace()自定义原型实例:

>>> Account = namedtuple('Account', 'owner balance transaction_count')
>>> default_account = Account('<owner name>', 0.0, 0)
>>> johns_account = default_account._replace(owner='John')

枚举的常量可以采用命名的元组,但它是更简单、 更高效地使用一个简单的类声明:

>>> Status = namedtuple('Status', 'open pending closed')._make(range(3))
>>> Status.open, Status.pending, Status.closed
(0, 1, 2)
>>> class Status:
        open, pending, closed = range(3)

请参见

命名元组配方适合使用 Python 2.4。

8.3.5. OrderedDict

序的字典是就像普通词典,但是他们记得被插入了项目的顺序。当遍历排序字典,项目将返回其键第一次添加的顺序。

class collections.OrderedDict([items])

返回一个字典子类,支持常用字典方法的实例。OrderedDict是 dict,记得键第一次插入顺序。如果一个新的条目将改写现有条目,离开了原来的插入位置不变。删除一个条目,然后重新插入将移动到结尾。

在 2.7 版本新。

OrderedDict.popitem(last=True)

序词典的popitem()方法返回并删除 (关键字,值) 对。按后进先出顺序如果最后是真实或 FIFO 顺序如果为 false 返回对。

除了通常的映射方法,下令词典也支持反向迭代使用reversed()

OrderedDict对象之间的平等测试顺序敏感,并作为list(od1.items())==list(od2.items())实现。 OrderedDict对象和其他映射的对象之间的平等测试是顺序不敏感的像常规的字典。这将允许OrderedDict对象要取代任何地方使用常规的词典。

OrderedDict的构造函数和update ()方法既接受关键字参数,但它们的顺序是丢失,因为 Python 的函数调用语义通 in 关键字参数使用常规的无序的字典。

请参见

运行使用 Python 2.4 或更高版本的等效 OrderedDict 食谱

8.3.5.1. OrderedDict

因为有序的字典记得其插入顺序,可以使用与排序,以使已排序的字典:

>>> # regular unsorted dictionary
>>> d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

>>> # dictionary sorted by key
>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

>>> # dictionary sorted by value
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

>>> # dictionary sorted by length of the key string
>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])

新的已排序的字典维护他们的排序顺序,当条目被删除。但是,当添加新的密钥,密钥追加到结尾和排序不会维护。

这也是直向前来创建记得钥匙是最后插入的顺序排序的字典变型。如果一个新的条目会覆盖现有的条目,原始的插入位置是改变并移至结尾处:

class LastUpdatedOrderedDict(OrderedDict):
    'Store items in the order the keys were last added'

    def __setitem__(self, key, value):
        if key in self:
            del self[key]
        OrderedDict.__setitem__(self, key, value)

可以与计数器类结合有序的字典,以便柜台记得订单元素第一次遇到:

class OrderedCounter(Counter, OrderedDict):
     'Counter that remembers the order elements are first encountered'

     def __repr__(self):
         return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))

     def __reduce__(self):
         return self.__class__, (OrderedDict(self),)

8.3.6. Collections Abstract Base Classes

collections模块提供以下抽象基类

ABC Inherits from Abstract Methods Mixin Methods
Container   __contains__  
Hashable   __hash__  
Iterable   __iter__  
Iterator Iterable next __iter__
Sized   __len__  
Callable   __call__  
Sequence Sized, Iterable, Container __getitem__, __len__ __contains__, __iter__, __reversed__, index, and count
MutableSequence Sequence __getitem__, __setitem__, __delitem__, __len__, insert Inherited Sequence methods and append, reverse, extend, pop, remove, and __iadd__
Set Sized, Iterable, Container __contains__, __iter__, __len__ __le__, __lt__, __eq__, __ne__, __gt__, __ge__, __and__, __or__, __sub__, __xor__, and isdisjoint
MutableSet Set __contains__, __iter__, __len__, add, discard Inherited Set methods and clear, pop, remove, __ior__, __iand__, __ixor__, and __isub__
Mapping Sized, Iterable, Container __getitem__, __iter__, __len__ __contains__, keys, items, values, get, __eq__, and __ne__
MutableMapping Mapping __getitem__, __setitem__, __delitem__, __iter__, __len__ Inherited Mapping methods and pop, popitem, clear, update, and setdefault
MappingView Sized   __len__
ItemsView MappingView, Set   __contains__, __iter__
KeysView MappingView, Set   __contains__, __iter__
ValuesView MappingView   __contains__, __iter__
class collections.Container
class collections.Hashable
class collections.Sized
class collections.Callable

Abc 方法__contains__() __hash__() __len__()__call__()分别提供的类。

class collections.Iterable

ABC 为提供了__iter__()方法的类的。另请参阅定义的可迭代

class collections.Iterator

ABC 为提供了__iter__()next ()方法的类的。另请参阅定义的迭代器

class collections.Sequence
class collections.MutableSequence

只读模式和可变序列的基本知识。

class collections.Set
class collections.MutableSet

只读模式和可变集基本要领。

class collections.Mapping
class collections.MutableMapping

只读模式和可变类型mappings的基类。

class collections.MappingView
class collections.ItemsView
class collections.KeysView
class collections.ValuesView

Abc 的映射、 项、 注册表项和值的意见

这些 Abc 请允许我们问类或实例,如果他们能提供特定的功能,例如:

size = None
if isinstance(myvar, collections.Sized):
    size = len(myvar)

几个 Abc 也是有用的因为 mixin 使它更易于开发支持容器 Api 的类。例如,若要编写支持完整设置API,它提供三种基本的抽象方法只需一个类: __contains__() __iter__() __len__()ABC 提供其余的方法,如__and__()isdisjoint()

class ListBasedSet(collections.Set):
     ''' Alternate set implementation favoring space over speed
         and not requiring the set elements to be hashable. '''
     def __init__(self, iterable):
         self.elements = lst = []
         for value in iterable:
             if value not in lst:
                 lst.append(value)
     def __iter__(self):
         return iter(self.elements)
     def __contains__(self, value):
         return value in self.elements
     def __len__(self):
         return len(self.elements)

s1 = ListBasedSet('abcdef')
s2 = ListBasedSet('defghi')
overlap = s1 & s2            # The __and__() method is supported automatically

使用设置MutableSet作为 mixin 的注意事项:

  1. Since some set operations create new sets, the default mixin methods need a way to create new instances from an iterable. The class constructor is assumed to have a signature in the form ClassName(iterable). That assumption is factored-out to an internal classmethod called _from_iterable() which calls cls(iterable) to produce a new set. If the Set mixin is being used in a class with a different constructor signature, you will need to override _from_iterable() with a classmethod that can construct new instances from an iterable argument.
  2. To override the comparisons (presumably for speed, as the semantics are fixed), redefine __le__() and __ge__(), then the other operations will automatically follow suit.
  3. The Set mixin provides a _hash() method to compute a hash value for the set; however, __hash__() is not defined because not all sets are hashable or immutable. To add set hashabilty using mixins, inherit from both Set() and Hashable(), then define __hash__ = Set._hash.

请参见