有序字典就像普通字典一样,但有一些与排序操作相关的额外功能。现在它们变得不那么重要了,因为内置dict类获得了记住插入顺序的能力(这种新行为在 Python 3.7 中得到保证)。

dict仍然存在一些差异:

  • 常规字典被设计成非常擅长映射操作。 跟踪插入顺序是次要的。
  • OrderedDict 旨在擅长重新排序操作。 空间效率、迭代速度和更新操作的性能是次要的。
  • 在算法上,OrderedDict 可以比 dict 更好地处理频繁的重新排序操作。 这使其适用于跟踪最近的访问(例如在 LRU 缓存中)。
  • OrderedDict检查匹配顺序的相等操作。
  • OrderedDict 的 popitem() 方法具有不同的签名。 它接受一个可选参数来指定弹出哪个项目。
  • OrderedDict 有一个 move_to_end() 方法可以有效地将元素重新定位到端点。
  • 在 Python 3.8 之前,dict 缺少 __reversed__() 方法。
class collections.OrderedDict([items])
返回一个子类的实例,该dict子类具有专门用于重新排列字典顺序的方法。

3.1 版中的新功能。

popitem(last=True)
有序字典的 popitem() 方法返回和删除 (key, value) 对。 如果 last 为真,则按 LIFO 顺序返回这些对,如果为假,则按 FIFO 顺序返回。
move_to_end(keylast=True)
将现有键移动到有序字典的任一端。 如果 last 为 true(默认值),则项目移动到右端;如果 last 为 false,则项目移动到开头。 如果密钥不存在则引发 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'

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

OrderedDict 对象之间的相等性测试是顺序敏感的,并且实现为 list(od1.items())==list(od2.items())。 OrderedDict 对象和其他 Mapping 对象之间的相等性测试与常规词典一样对顺序不敏感。 这允许在使用常规字典的任何地方替换 OrderedDict 对象。

在 3.5 版更改:OrderedDict 的项、键和值视图现在支持使用 reversed() 进行反向迭代。

在 3.6 版更改:随着 PEP 468 的接受,保留传递给 OrderedDict 构造函数及其 update() 方法的关键字参数的顺序。

OrderedDict 示例和方法
创建一个有序的字典变体很简单,它可以记住上次插入键的顺序。 如果一个新的条目覆盖了一个现有的条目,原来的插入位置被改变并移动到末尾:

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

    def __setitem__(self, key, value):
        super().__setitem__(key, value)
        super().move_to_end(key)

OrderedDict 也可用于实现 functools.lru_cache() 的变体:

class LRU(OrderedDict):
    'Limit size, evicting the least recently looked-up key when full'

    def __init__(self, maxsize=128, *args, **kwds):
        self.maxsize = maxsize
        super().__init__(*args, **kwds)

    def __getitem__(self, key):
        value = super().__getitem__(key)
        self.move_to_end(key)
        return value

    def __setitem__(self, key, value):
        super().__setitem__(key, value)
        if len(self) > self.maxsize:
            oldest = next(iter(self))
            del self[oldest]