【问题标题】:Is the key order the same for OrderedDict and dict?OrderedDict 和 dict 的键顺序是否相同?
【发布时间】:2021-10-26 12:52:06
【问题描述】:

dict 自 Python 3.6 以来一直保持插入顺序(请参阅this)。

OrderedDict 就是为此目的而开发的(在 Python 3.6 之前)。

自 Python 3.6 起,dictOrderedDict 的键顺序是否始终相同?

我想知道我是否可以在我的代码中执行此操作并且始终具有相同的行为(除了相等性和OrderedDict 中的一些扩展方法)但更有效:

if sys.version_info[:2] >= (3, 6):
  OrderedDict = dict
else:
  from collections import OrderedDict 

或者换个说法,对于 Python >=3.6,有什么理由使用OrderedDict

【问题讨论】:

标签: python


【解决方案1】:

OrderedDictdict 都是按插入顺序进行迭代的¹。如果迭代顺序是唯一的决定点,则实际上没有理由使用OrderedDict,尤其是在不需要重新排序的情况下。
显然,如果需要 比较 顺序,OrderedDictdict 是不可互换的。

或者换个说法,对于 Python >=3.6,有什么理由使用OrderedDict

这些天OrderedDictdict 什么dequelist,基本上。 OrderedDict/deque 基于链表²,而 dict/list 基于数组。前者具有更好的 pop/move/FIFO 语义,因为项目可以从开始/中间移除而不移动其他项目。

由于数组通常对缓存非常友好,因此链表的优势只在非常大的容器中发挥作用。此外,OrderedDict(与deque 不同)不保证其链表语义,因此其优势可能无法移植。 OrderedDict 应该主要用于需要许多 pop/move/FIFO 操作并且基准测试可以在实践中比较 dictOrderedDict 的性能。


¹这适用于所有当前支持的符合 Python 语言规范的实现,即自 Python 3.6 以来的 CPython 和 PyPy。

²OrderedDict 在 CPython 中仍然保留 O(1) 密钥访问。这是通过有一个“常规”查找表来实现的,使用链接列表来项之间的订单和直接项访问的查找表.很复杂。

【讨论】:

  • OrderedDict中的链表只是用来存储key order的,不是mapping本身,只是一个普通的dict。虽然我想知道为什么OrderedDict实际上需要存储密钥顺序,如果它无论如何都是一样的。
  • @Albert 使用move_to_end(可能还有其他方法)时,链表顺序和项目顺序(即dict的排序/存储)不一样。链表还允许直接访问“第一个”/“最后一个”项目,而 dict 项目存储需要扫描这些以跳过无人居住的插槽。
  • 对了。尽管这些是我的用例永远不需要的东西(我唯一需要的是键的插入顺序,仅此而已)。所以听起来我应该只使用dictdict 甚至有我想要的比较。
【解决方案2】:

我意识到相等的不同行为 (__eq__) 实际上可能是一个主要问题,为什么这样的代码 sn-p 可能不好。

但是,您也许仍然可以这样做:

if sys.version_info[:2] >= (3, 6):
  OrderedDict = dict
else:
  from collections import OrderedDict as _OrderedDict

  class OrderedDict(_OrderedDict):
    __eq__ = dict.__eq__
    __ne__ = dict.__ne__

不同的是,和原来的collections.OrderedDict{1:1,2:2}{2:2,1:1}不一样,但是这个例子中dict和我覆盖的OrderedDict是一样的。

【讨论】:

  • 可能值得对此进行扩展 - 有些读者可能不知道 dicts 与 OrderedDicts 的相等性之间的区别。
【解决方案3】:

有些行为保持不变,但 OrderedDict 是可逆的,而 dict 不是:

from collections import OrderedDict

d = { "a" : 1, "c" : 2}

od = OrderedDict(d.items())

print(list(reversed(od)))
print(list(reversed(d)))

输出

['c', 'a']

Traceback (most recent call last):
  File "path/to/file", line 8, in <module>
    print(list(reversed(d)))
TypeError: 'dict' object is not reversible

来自documentation

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

【讨论】:

  • 从 Python 3.8 开始,reversed 确实适用于常规的 dict。见doc
  • 你能更具体地谈谈“某些行为”吗?哪种行为完全不同(Python 3.6 和 3.7 中的可逆行为除外)?或者反过来问,尽管如此,一切都一样?
  • 当我指的是某些行为时,其余部分当然是 OrderedDict 中存在的不在 dict 中的方法。出于好奇,你为什么要做这样的事情?
  • 使用dict应该比OrderedDict快很多。
猜你喜欢
  • 2020-02-07
  • 1970-01-01
  • 1970-01-01
  • 2020-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-12
  • 2012-04-09
相关资源
最近更新 更多