【问题标题】:Difference in performance of two seemingly similar dict statements? [duplicate]两个看似相似的 dict 语句的性能差异? [复制]
【发布时间】:2017-06-21 18:08:30
【问题描述】:

“要避免的一个问题是确保你这样做:key in some_dict 而不是 key in some_dict.keys()。两者在语义上是等效的,但在性能方面后者要慢得多(O(n) vs O(1 ))。我看到人们使用in dict.keys() 认为它更明确,因此更好。”

我在网上找到了这条建议。谁能解释并证明上述性能差异?这两个看似相似的语句的工作原理有何不同?

编辑:更准确地说,如何在字典中建立索引比在列表中建立索引更快?据我所知,哈希表是链表的数组。数组是键的数组。因此,在哈希表中查找键应该类似于在键列表中查找该键。 (?)

【问题讨论】:

  • 你熟悉hash tables的理论吗?
  • @PM2Ring 我确实在 C 中实现了它。所以我会说是的,我熟悉数据结构。我错过了什么明显的东西吗?
  • 另一个类似的问题stackoverflow.com/questions/1602934/…
  • 您应该阅读 Laurent Luce 关于Python dictionary implementation 的这篇文章。 dict 对象的确切实现在 Python 3.6 中发生了变化,但散列过程仍然非常相似,AFAIK。由于您可以读写 C,因此查看dictobject.c 源代码可能会有所帮助。
  • This answer by Jim Fasarakis-Hilliard 简要解释了新的 Python 3.6 字典。

标签: python performance


【解决方案1】:

仅适用于 Python 2。

在 Python 3 中,dict.keys() 返回一个视图对象 dict_keys,它包装了源 dict 对象:

$ python3
Python 3.5.2 (default, Nov 17 2016, 17:05:23)
>>> d = { 1: 11, 2:22, 3:33 }
>>> k = d.keys()
>>> k
dict_keys([1, 2, 3])
>>> d
{1: 11, 2: 22, 3: 33}
>>> d[4] = 44
>>> k
dict_keys([1, 2, 3, 4])  #!!! k includes the new key that was added to d
>>> 

因此,在 Python 3 中,key in dict.keys() 的执行效率几乎与 key in dict 一样:

  1. dict.keys() 在 O(1) 时间内创建 dict_keys 对象,然后
  2. 查询操作通过dict_keys 重新路由回dict,后者在 O(1) 时间内执行。

与 Python 3 不同,在 Python 2 中,dict.keys() 返回一个必须在 O(n) 时间内构建的列表对象:

$ python2
Python 2.7.12 (default, Nov 19 2016, 06:48:10) 
>>> d = { 1: 11, 2:22, 3:33 }
>>> k = d.keys()
>>> k
[1, 2, 3]
>>> d[4] = 44
>>> k
[1, 2, 3]
>>> 

因此,在 Python 2 中,key in dict.keys()(作为测试,而不是作为for key in dict.keys() 的一部分)将有两个O(n) 时间复杂度来源:

  1. 构建 dict.keys() 返回的列表需要 O(n) 时间
  2. 检查查询值是否在返回列表中需要另一个 O(n) 时间。

【讨论】:

  • 不仅列表构建时间为 O(n),列表搜索时间也是 O(n),因为 k in some_list 执行线性扫描。您的回答确实应该提到这一点。这两个操作都以 C 的速度执行,因此它们比使用显式 Python 循环执行它要快得多,但避免这些不必要的操作当然是明智的。
  • @PM2Ring 你是对的。假设 element in setfor 循环的上下文中使用,我不知何故误读了这个问题。
  • Python 3 dict.keys() 是一个view object,它类似于集合,尽管它不完全是集合。 Python 2 dict.keys() 是一个普通的旧静态列表。
  • 我不知道你为什么投了反对票。也许投反对票的人不明白你的答案......
  • @Leon 哦,好吧!一个“视图对象”。这对我来说是全新的。我得调查一下。谢谢。 :)
猜你喜欢
  • 1970-01-01
  • 2019-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-19
  • 2021-02-07
  • 1970-01-01
相关资源
最近更新 更多