# 8.3. `collections` — 容器数据类型

源代码： Lib/collections/__init__.py

这个模块实现了专业的容器数据类型用来替代Python的通用内置容器，`字典`, `列表`, `集合`, 和 `元组`.

`namedtuple()` | 这是个工厂方法,生成有命名字段的tuple子类(译注: tuple中的元素可以用名字的方式来访问)
`deque`(双向队列) | 一个能在“队列”两端快速出队、入队的，类似于队列的（list-like）的容器 (译者注:就是双向队列)
`ChainMap` | 为多个映射创建单一视图的类字典类型 (译者注:模仿作用域搜索)
`Counter`(计数器) | dict子类，用于计算可哈希对象的个数
`OrderedDict`（有序字典） | dict 子类 记录着数据成员添加的顺序
`defaultdict` | 调用一个工厂函数来为dict的values缺失提供值
`UserDict` | 将字典包裹起来使得创建字典的子类更容易
`UserList` | 将列表对象包裹起来使得创建列表的子类更容易
`UserString` | 将字符串对象包裹起来使得创建字符串的子类更容易

在版本3.3中更改：已将容器抽象基类移动到`collections.abc`模块。为了向后兼容，它们在该模块中也是可见的。

## 8.3.1.`ChainMap`对象

版本3.3中的新功能。

`ChainMap`类对象提供一个链接多个mappings的单一单元。它比创建一个新字典和运行 `update()`方法要快。

ChainMap用于模仿内嵌作用域和作为模板

class `collections.``ChainMap`(*maps)

  一个 `ChainMap`组合多个字典或其它映射集创建一个单一且可更新的视图。如果没有指定 maps ，那么将会用一个空字典作为新chain里面的一个mapping

  基础的mappings被存储在一个列表当中。这个列表是公开的，可以用 maps 属性访问和更新。没有其它的情况。

  使用查找功能会在基础的mappings查找，直到一个key被找到（译者注：相当于通过LEGB法则搜索）。相比较而言，创建键值对，更新键值对，删除键值对，仅仅在第一个mapping里面进行（译者注：相当于local）。

  通过引用，基础的映射集组合成`ChainMap`。所以，如果基础映射集（mappings）里面的一个mapping被更新，则这些改变都会反映在`ChainMap`。

  在ChainMap中dict的所有方法都适用。另外，ChainMap还有一个maps属性，new_child(m=None)方法用于创建一个新的子空间，parents属性访问除第一个mapping以外的映射集。

  `maps`

    用户可更新的mappings列表（译者注：修改它，也会修改ChainMap()）。此列表是有序的，从第一个mapping到最后一个mapping。此列表仅仅存储状态，并且可以通过改变一个mapping来修改这个列表。此列表应该总是至少包含一个mapping。

  `new_child`(m=None)

    返回一个新的 `ChainMap`，它包含一个新的map和当前实例的所有maps。如果指定`m`参数，那么它会成为新maps列表里面的第一个map; 如果没有被给,那么将会使用空字典作为第一个map,所以调用`d.new_child()` 等价于: `ChainMap({}, *d.maps)`.。此方法用于创建子空间，当子空间的值被更新将不会影响父mappings里面的任何值。

    在Changed in version 3.4中:选项 `m`参数被增加。

  `parents`

    parents属性返回一个新的`ChainMap`，它包含当前实例的除第一个map的所有maps。这个可以用于在搜索中跳过第一个map。在 内嵌作用域中的使用与关键字 `nonlocal` 相似。这个用法与内建的`super()` 函数相似。`d.parents` 相当于: `ChainMap(*d.maps[1:])`.

请参见

- Enthought CodeTools包中的MultiContext类具有支持写入链中任何映射的选项。
- Django的上下文类用于模板化是只读链接的映射。它还具有类似于`new_child()`方法和`parents()`属性的上下文推送和弹出功能。
- 嵌套上下文配方具有控制写入和其他突变是否仅应用于链中的第一个映射或任何映射的选项。
- 极大地简化了Chainmap的只读版本。

### 8.3.1.1.`ChainMap`示例和配方

此部分展示不同的ChainMap的用法。

模仿python内部查找作用域链的例子：

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

让用户指定的命令行参数优先于环境变量的示例，这些环境变量的优先级高于默认值：

    import os, argparse

    defaults = {'color': 'red', 'user': 'guest'}

    parser = argparse.ArgumentParser()
    parser.add_argument('-u', '--user')
    parser.add_argument('-c', '--color')
    namespace = parser.parse_args()
    command_line_args = {k:v for k, v in vars(namespace).items() if v}

    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']                # Get first key in the chain of contexts
    d['x'] = 1            # Set value in current context
    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

当通过搜索整个链时（不是特定某个mapping），`ChainMap` 类仅仅只能更新，添加，删除第一个mapping（相当于locale）里面的键值对。然而，如果需要操作后面的mapping（相当于global），可以很容易通过创建一个子类来更新后面的mapping：

    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
    DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})

## 8.3.2.`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])

  `Counter`是`dict`的子类，用于计数可哈希对象。它是一个无序的容器，元素被存储为字典键，它们的计数被存储为字典值。计数允许包括零或负计数的任何整数值。`Counter`类与其他语言的bags或multisets类似。

  它的元素从一个可迭代对象计数，或从另一个映射（或计数器）初始化：

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

  版本3.1中的新功能。

  计数器对象支持除了对所有字典可用的方法之外的三种方法：

  `elements`()

    返回一个迭代器，对元素重复迭代其计数次。元素以随机顺序返回。如果元素的计数小于1，`elements()`将忽略它。

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

  `most_common`([n])

    返回n个最常见的元素及其计数的列表，从最常见到最少见。如果省略n或为`None`，`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})

    版本3.2中的新功能。

  除了两个字典方法对计数器工作不同，通常的都适用于`Counter`对象。

  `fromkeys`(iterable)

    这个类方法未针对`Counter`对象实现。

  `update`([iterable-or-mapping])

    元素从一个可迭代对象计数或从另一个映射（或计数器）增加。类似`dict.update()`，但增加计数，而不是替换它们。此外，可迭代对象应为一系列元素，而不是`(key, value)`对。

使用`计数器`对象的常见模式：

    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                              # remove zero and negative counts

几个数学运算被提供以组合`Counter`对象来产生multisets（计数器大于零的计数器）。加法和减法通过相加或相减相应元素的计数来组合计数器。交集和并集返回相应计数的最小值和最大值。每个操作的输入都可以接受带有符号的计数，但输出将排除计数为零或更少的结果。

    >>> 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 = Counter(a=2, b=-4)
    >>> +c
    Counter({'a': 2})
    >>> -c
    Counter({'b': 4})

版本3.3中的新功能：添加了对一元加号，一元减号和就地多元组操作的支持。

注意

计数器主要设计为使用正整数表示运行计数；但是，需要注意不要不必要地排除需要其他类型或负值的用例。为了帮助这些用例，本节记录最小范围和类型限制。

- `Counter`类本身是一个字典子类，对其键和值没有限制。这些值用于表示计数的数字，但你可以在值字段中存储任何内容。
- `most_common()`方法只需要这些值是可排序的。
- 对于诸如`c[key] += 1`之类的就地操作，值类型只需要支持加法和减法。因此，分数、浮点数和小数可以工作，支持负值。对于`update()`和`subtract()`也是如此，其允许输入和输出的负值和零值。
- Multiset方法仅用于具有正值的用例。输入可以是负或零，但是仅创建具有正值的输出。没有类型限制，但值类型需要支持加、减和比较。
- `elements()`方法需要整数计数。它忽略零和负计数。

也可以看看

- Smalltalk中的Bag class。

- Multisets的维基百科条目。

- C++ multisets教程与示例。

- 对于multisets的数学运算及其用例，参见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

## 8.3.3. `deque`对象

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

  返回一个由迭代器从左到右(使用`append()`)初始化的双向队列.若未指定初始化的迭代器，返回的双向队列的长度为0

  双向队列（Deque）是栈和队列的一般化（deque发音和‘deck’一样，是‘double-ended queue’的缩写）。Deque是线程安全的。在队列两端添加（append）或弹出（pop）元素的复杂度大约是O(1),所以Deque的效率是很高的。

  尽管`list` 对象支持类似的操作, 但是list是专门为固定长度的操作进行了优化，导致了改变列表长度和数据位置的操作例如 `pop(0)`和 `insert(0, v)` 操作的复杂度高达O(n)

  如果 maxlen 未指定或为 None，deque可能长到任意长度。否则，deque的最大长度为指定的maxlen。一旦有界的双向队列满了以后，当有新的元素添加到队列中，就会有相应数量的元素在另一端被丢弃。有界双向队列提供了类似于Unix中`tail`过滤器的功能。They are also useful for tracking transactions and other pools of data where only the most recent activity is of interest.（译者：只能意会，翻译不了T_T）

  双向队列的对象支持一下方法:

  `append`(x)

    x 从右端入队.

  `appendleft`(x)

    x 从左端入队.

  `clear`()

    清空队列中的所有元素，deque的长度变为0.

  `copy`()

    对deque进行浅复制.

    版本3.5中的新功能。

  `count`(x)

    计算deque中值等于 x 的个数.

    版本3.2中的新功能。

  `extend`(iterable)

    往deque的右端添加迭代器的元素

  `extendleft`(iterable)

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

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

    在deque中返回x的位置（在索引开始之后或索引停止之前）。如果未找到，则返回第一个匹配或引发`ValueError`。

    版本3.5中的新功能。

  `insert`(i, x)

    将x插入到位置i的deque中。

    如果插入将导致有界deque增长超过maxlen，则会引发`IndexError`。

    版本3.5中的新功能。

  `pop`()

    删除并从右侧的双端队列中返回的元素。如果没有元素，则引入`IndexError`。

  `popleft`()

    移除并返回一个元素从 deque 的左侧。如果没有元素，则引入`IndexError`。

  `remove`(value)

    删除值的第一次出现。如果未找到，请引发`ValueError`。

  `reverse`()

    反转deque的元素，然后返回`None`。

    版本3.2中的新功能。

  `rotate`(n)

    将deque向右旋转n 个元素。如果 n 是负数, 则向左旋转.向右旋转1个元素等价于`d.appendleft(d.pop())`.

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

  `maxlen`

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

    版本3.1中的新功能。

除了上述，deques支持迭代，pickle序列化，`len(d)`，`reversed(d)`，`copy.copy(d)` `copy.deepcopy(d)`，使用`in`操作符号中的成员资格测试，以及诸如`d[-1]`的下标引用。索引的访问两端都是 o (1)，但速度就减慢到 o (n) 在中间。对于快速的随机访问，改用列表。

从版本3.5开始，deques支持`__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'])

### 8.3.3.1. `deque`使用方法

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

边界长度deques提供类似于Unix中的`tail`过滤器的功能：

    def tail(filename, n=10):
        'Return the last n lines of a file'
        with open(filename) as f:
            return deque(f, 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 / 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()`添加新条目，然后反转旋转。With minor variations on that approach, it is easy to implement Forth style stack manipulations such as `dup`, `drop`, `swap`, `over`, `pick`, `rot`, and `roll`.

## 8.3.4. `defaultdict`对象

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

  返回一个新的类似字典的对象。`defaultdict`是内置`dict`类的子类。它覆盖一个方法，并添加一个可写的实例变量。其余的功能与`dict`类相同，这里就不再记录。

  第一个参数提供`default_factory`属性的初始值；它默认为`None`。所有剩余的参数都视为与传递给`dict`构造函数的参数相同，包括关键字参数。

  `defaultdict`对象除了支持标准的`dict`操作，还支持以下方法：

  `__missing__` （ key ）

    如果`default_factory`属性为`None`，则以key作为参数引发`KeyError`异常。

    如果`default_factory`不为`None`，则不带参数调用它以用来给key提供默认值，此值将插入到字典中用于key，并返回。

    如果调用`default_factory`引发异常，则该异常会保持原样传播。

    当未找到请求的key时，此方法由`dict`类的`__getitem__()`方法调用；`__getitem__()`将返回或引发它返回或引发的。

    请注意，除了`__getitem__()`之外的任何操作，都不会调用`__missing__()`。这意味着`get()`会像正常的字典一样返回`None`作为默认值，而不是使用`default_factory`。

  `defaultdict`对象支持以下实例变量：

  `default_factory`

    此属性由`__missing__()`方法使用；如果构造函数的第一个参数存在，则初始化为它，如果不存在，则初始化为`None`。

### 8.3.4.1. `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])]

当每个键第一次遇到时，它不在映射中；因此使用返回空`list`的`default_factory`函数自动创建一个条目。然后，`list.append()`操作将值附加到新列表。当再次遇到这个键时，查找正常继续（返回该键的列表），并且`list.append()`操作向列表中添加另一个值。这种技术比使用等效的`dict.setdefault()`技术更简单和更快：

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

将`default_factory`设置为`int`可使`defaultdict`用于计数（如其他语言的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)]

当一个字母第一次遇到时，映射中缺少该字母，因此`default_factory`函数调用`int()`以提供默认计数零。后面，这个增量操作将建立每个字母的计数。

始终返回零的函数`int()`只是常量函数的特殊情况。创建常量函数的更快和更灵活的方法是使用lambda函数，它可以提供任何常量值（不只是零）：

    >>> 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_factory`设置为`set`可使`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)
    ...
    >>> sorted(d.items())
    [('blue', {2, 4}), ('red', {1, 3})]

## 8.3.5. `namedtuple()`工厂函数，用于具有命名字段的元组

命名元组赋予元组中的每个位置一定的含义，允许更具可读性、自带文档的代码。它们可以用作常规元组可以使用的任何地方，并且它们添加能够按名称而不是位置索引字段的能力。

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

  返回一个叫做typename的新的元组子类。这个新的子类用来创建类元组对象，这个对象拥有可以通过属性访问的字段，并且可以通过下标索引和迭代。这个子类的实例还拥有十分友好的文档字符串（包括类型名和字段名）和十分好用的`__repr__()` 方法，以`name=value`的方式列出了元组中的内容。

  field_names是单个字符串，其中的每个字段用空格或逗号隔开，例如 `'x y'`或`'x, y'`。另外，field_names可以是字符串的列表，例如`['x', 'y']`。

  除了以下划线开头的名称，任何有效的 Python 标识符都可用于 fieldname 。有效的标识符由字母、 数字和下划线组成，但是不能以数字或下划线开头，并且不能是 `关键字` 例如 class、 for、 return、 global、 pass 或 raise。

  如果 rename参数 为 True, 无效的字段名会被自动转换成位置的名称.例如, `['abc', 'def', 'ghi', 'abc']` 将被转换为 `['abc', '_1', 'ghi', '_3']`, 来消除关键字 `def` 和重复的字段名 `abc`.

  如果verbose为真，则在构建它后将打印这个类的定义。此选项已过时；相反，打印`_source`属性更简单。

  命名元组没有在每个实例中包含一个字典, 所以它们是轻量级的，并不会比常规的元组消耗更多的内存。

  对于简单使用，其中唯一的要求是能够使用属性样式访问通过名称引用一组值，`types.SimpleNamespace`类型可以是使用命名的元组的合适替代。

  在版本3.1中已更改：添加了对重命名的支持。

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

namedtuple 在为 `csv` or `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)

除了从tuple继承而来的方法，namedtuple还支持另外三个方法和两个属性。为了避免和字段冲突，这些方法和属性都以下划线开头

classmethod `somenamedtuple.``_make`(iterable)

  类方法。从现有的列表或迭代器创建一个新的实例

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

`somenamedtuple.``_asdict`()

  返回一个`OrderedDict(有序字典)`，每个键对应于该字段的值

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

  在版本3.1中更改：返回`OrderedDict`，而不是常规`dict`。

`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.``_source`

  一个带有纯Python源代码的字符串，用于创建命名的tuple类。源使得命名的元组自我记录。它可以打印，使用`exec()`执行，或保存到文件并导入。

  版本3.3中的新功能。

`somenamedtuple.``_fields`

  字段名称的元组。在自我检查和从已有的namedtuple创建新的namedtuple非常有用。

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

要将字典转换为命名的元组，请使用双星运算符（如Unpacking Argument Lists中所述）：

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

可以通过对`__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版本中已更改：属性文档字符串变得可写。

默认值可以通过使用`_replace()`实现原型实例：

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

请参见

- 由Jan Kaliszewski提供的具有元类混合的命名元组抽象基类的配方。除了为命名元组提供abstract base class，它还支持一个替换的metaclass构造函数，便于对命名元组进行子类化的用例。

## 8.3.6.`OrderedDict`对象

有序字典与常规字典类似，但它们记住项目插入的顺序。当对有序字典进行迭代时，项目按它们的键首次添加的顺序返回。

class `collections.``OrderedDict`([items])

  返回一个dict子类的实例，支持通常的`dict`方法。OrderedDict是记住键首次插入顺序的字典。如果新条目覆盖现有条目，则原始插入位置保持不变。删除条目并重新插入会将其移动到末尾。

  版本3.1中的新功能。

  `popitem`(last=True)

    有序字典的`popitem()`方法返回并删除(key, value)对。如果last为真，则以LIFO顺序返回这些键值对，如果为假，则以FIFO顺序返回。

  `move_to_end`(key, last=True)

    将一个已存在key移动到有序字典的任一端。如果last为真（默认值），则项目移动到末尾，如果last为假，则移动到开始。如果key不存在，引发`KeyError`：

        >>> d = OrderedDict.fromkeys('abcde')
        >>> d.move_to_end('b')
        >>> ''.join(d.keys())
        'acdeb'
        >>> d.move_to_end('b', last=False)
        >>> ''.join(d.keys())
        'bacde'

    版本3.2中的新功能。

除了通常的映射方法之外，有序字典还支持使用`reversed()`的反向迭代。

`OrderedDict`对象之间的相等性测试是顺序敏感的，并且实现为`list(od1.items())==list(od2.items())`。`OrderedDict`对象与其他`映射`对象之间的相等性测试与常规字典类似，对顺序不敏感。这允许在使用常规字典的任何位置替换`OrderedDict`对象。

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

在版本3.5中更改：`OrderedDict`的项目、键和值视图现在支持使用`reversed()`的反向迭代。

### 8.3.6.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)

有序字典可以与`Counter`类结合，以便计数器记住首次遇到的顺序元素：

    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.7.`UserDict`对象

`UserDict`是一个包裹了字典的对象。对这个类的需要已经部分地被直接从`dict`子类化的能力所代替；但是，此类可以更容易使用，因为底层字典可作为属性访问。

class `collections.``UserDict`([initialdata])

  UserDict仿照字典。实例的内容保存在一个普通的字典当中，可以通过`UserDict`实例的属性`data`访问。如果提供initialdata, `data`就会被初始化为initialldata; note that a reference to initialdata will not be kept, allowing it be used for other purposes.

  除了支持一些方法和mappings的操作外，`UserDict`还提供以下属性：

  `data`

    data属性是存储`UserDict`类内容的真正字典。

## 8.3.8.`UserList`对象

这个类充当列表对象的包装器。它是一个有用的基类，你自己的类列表类可以从它们继承，覆盖现有的方法或添加新的。这样，可以向列表中添加新的行为。

这个类的需要已经部分地被直接从`list`子类化的能力所取代；但是，此类可以更容易使用，因为底层列表可作为属性访问。

class `collections.``UserList`([list])

  模拟列表的类。实例的内容保存在常规列表中，可以通过`UserList`实例的`data`属性访问。实例的内容最初设置为列表的副本，默认为空列表`[]`。列表可以是任何可迭代的，例如真实的Python列表或`UserList`对象。

  除了支持可变序列的方法和操作，`UserList`实例提供以下属性：

  `数据`

    用于存储`UserList`类的内容的实际`list`对象。

子类要求： `UserList`的子类应提供一个构造函数，可以使用无参数或一个参数进行调用。列表操作返回一个新序列，尝试创建实际实现类的实例。为此，假设可以使用单个参数调用构造函数，该参数是用作数据源的序列对象。

如果派生类不希望遵守这个要求，这个类支持的所有特殊方法都需要被覆盖；请查阅来源，了解在这种情况下需要提供的方法的信息。

## 8.3.9.`UserString`对象

类`UserString`充当字符串对象的包装器。这个类的需要已经部分地被从`str`直接子类化的能力所取代；但是，此类可以更容易使用，因为底层字符串可作为属性访问。

class `collections.``UserString`([sequence])

  模拟字符串或Unicode字符串对象的类。实例的内容保存在常规字符串对象中，可通过`UserString`实例的`data`属性访问。实例的内容最初设置为序列的副本。序列可以是`bytes`，`str`，`UserString`（或子类）可以使用内建`str()`函数转换为字符串。

  在版本3.5中已更改：新方法`__getnewargs__`，`__rmod__`，`casefold`，`format_map` `isprintable`和`maketrans`。