OrderedDict 是 Python 标准库 collections 模块中的一个特殊字典,它像普通字典一样存储键值对,但它会记住键值对被插入的顺序。

这个特性在 Python 3.7 之前非常重要,因为当时标准的 dict 是无序的,从 Python 3.7 开始,标准的 dict 也开始保持插入顺序(在 Python 3.7 中是 CPython 的实现细节,在 Python 3.8+ 中成为语言规范的一部分)。
尽管如此,OrderedDict 仍然有其独特的用途,并且在某些特定场景下比普通 dict 更有优势。
OrderedDict 的基本用法
你需要从 collections 模块中导入它。
from collections import OrderedDict
创建和插入元素
OrderedDict 的创建和插入方式与普通字典类似。

# 创建一个空的 OrderedDict
od1 = OrderedDict()
# 使用构造函数创建
od2 = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# 添加键值对
od1['name'] = 'Alice'
od1['age'] = 30
od1['city'] = 'New York'
print(od1)
# 输出: OrderedDict([('name', 'Alice'), ('age', 30), ('city', 'New York')])
可以看到,打印出来的顺序和我们插入的顺序完全一致。
访问和修改元素
访问和修改元素的行为与普通 dict 相同,但要注意修改一个已存在的键不会改变它在字典中的顺序。
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# 访问元素
print(od['a']) # 输出: 1
# 修改已存在的键
print("修改前:", od)
od['b'] = 99
print("修改后:", od)
输出:
修改前: OrderedDict([('a', 1), ('b', 2), ('c', 3)])
修改后: OrderedDict([('a', 1), ('b', 99), ('c', 3)])
可以看到,'b' 的值虽然变了,但它的位置仍然在第二个。

删除元素
使用 popitem() 方法可以删除元素,这是 OrderedDict 的一个重要特性。
od.popitem(): 默认删除并返回最后一个插入的键值对 (LIFO - Last-In, First-Out)。od.popitem(last=False): 删除并返回第一个插入的键值对 (FIFO - First-In, First-Out)。
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# 默认删除最后一个
item_last = od.popitem()
print("删除的最后一个:", item_last)
print("删除后:", od)
# 删除第一个
item_first = od.popitem(last=False)
print("删除的第一个:", item_first)
print("删除后:", od)
输出:
删除的最后一个: ('c', 3)
删除后: OrderedDict([('a', 1), ('b', 2)])
删除的第一个: ('a', 1)
删除后: OrderedDict([('b', 2)])
OrderedDict 与普通 dict 的核心区别
尽管普通 dict 现在也保持顺序,但 OrderedDict 在以下方面有所不同:
| 特性 | OrderedDict |
普通 dict (Python 3.7+) |
|---|---|---|
| 内存占用 | 更高,为了维护顺序,它内部使用了额外的双向链表结构。 | 更低,实现更高效,内存占用更少。 |
| 迭代性能 | 稳定,迭代顺序总是插入顺序,性能可预测。 | 稳定,迭代顺序也是插入顺序。 |
popitem() |
灵活,支持 popitem() 和 popitem(last=False)。 |
受限,只支持 popitem(),默认删除最后一个。 |
| 相等性判断 | 顺序敏感。OrderedDict({'a': 1, 'b': 2}) != OrderedDict({'b': 2, 'a': 1}) |
顺序不敏感。{'a': 1, 'b': 2} == {'b': 2, 'a': 1} (值相同即相等) |
| 移动元素 | 支持,有 move_to_end() 方法,可以轻松地将一个键移动到字典的开头或结尾。 |
不支持,没有内置方法可以直接移动键的顺序。 |
OrderedDict 的核心方法详解
move_to_end(key, last=True)
这是 OrderedDict 最强大的方法之一,它可以将一个已存在的键移动到字典的末尾(last=True,默认)或开头(last=False)。
示例:
from collections import OrderedDict
od = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
print("原始顺序:", od)
# 将 'b' 移动到末尾
od.move_to_end('b')
print("'b' 移到末尾:", od)
# 将 'c' 移动到开头
od.move_to_end('c', last=False)
print("'c' 移到开头:", od)
输出:
原始顺序: OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
'b' 移到末尾: OrderedDict([('a', 1), ('c', 3), ('d', 4), ('b', 2)])
'c' 移到开头: OrderedDict([('c', 3), ('a', 1), ('d', 4), ('b', 2)])
何时应该使用 OrderedDict?
既然普通 dict 也有序了,为什么还要用 OrderedDict?
- 需要 LIFO/FIFO 队列行为:当你需要一个字典,并且需要频繁地从开头或结尾弹出元素时,
OrderedDict的popitem(last=False)和popitem()非常方便。 - 需要显式地移动元素顺序:如果你需要频繁地将某个键移动到字典的开头或结尾(实现一个最近使用过的缓存),
move_to_end()是最佳选择。 - 需要顺序敏感的字典比较:如果你需要两个字典不仅内容相同,插入顺序也必须相同时,
OrderedDict是唯一的选择。 - 代码可读性和意图:在代码中使用
OrderedDict可以明确地向其他开发者表明:“这个字典的顺序是至关重要的,请不要随意假设或改变它。”
如何将 OrderedDict 转换为普通 dict?
这非常简单,只需要用普通 dict 的构造函数即可。
from collections import OrderedDict
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# 直接转换
d = dict(od)
print(d)
# 输出: {'a': 1, 'b': 2, 'c': 3}
print(type(d))
# 输出: <class 'dict'>
# 在 Python 3.7+ 中,顺序会被保留
print(od == d)
# 输出: True
| 特性 | 普通字典 (dict) |
有序字典 (OrderedDict) |
|---|---|---|
| 核心用途 | 通用键值对存储 | 需要维护插入顺序的特殊键值对存储 |
| 内存 | 高效 | 较高 |
| 顺序保证 | Python 3.7+ 保证 | 始终保证 |
popitem |
只能从末尾删除 | 可从末尾或开头删除 |
move_to_end |
无 | 有,非常灵活 |
| 选择建议 | 默认选择,除非你有特殊需求,否则总是优先使用 dict。 |
特定场景,当你需要 FIFO/LIFO、move_to_end 或显式地表示顺序很重要时使用。 |
