元组是否可哈希,因此它们比list快吗?

时间:2018-08-04 02:41:27

标签: python python-3.x

我的老师说,元组比列表快,因为元组是不可变的,但我不明白原因。 我个人认为元组比列表快,因为元组是可哈希的,列表不可哈希。

请告诉我我是对还是错。

1 个答案:

答案 0 :(得分:10)

不,可散列与提高速度无关。

  

为了访问可哈希的集合中的元素,需要恒定的时间。

您正在使事情倒退。在使用哈希表(如set)的集合中查找可哈希元素的时间是恒定的。但这是关于元素是可哈希的,而不是集合,是关于使用哈希表而不是数组的集合,而是关于按值而不是按索引查找它们。

通过索引查找数组中的值(无论该值或数组是否可哈希)都需要固定的时间。通过值搜索数组需要线性时间。 (除非,例如,对它进行了排序,并且您通过二等分搜索。)


您的老师仅是部分正确的想法,但后来他们可能一直在简化事情,以避免陷入棘手的细节中。

在某些操作中,元组比列表快的原因有三个。

但是值得注意的是,这些差异通常很小,并且通常很难预测。 1 几乎总是,您只想使用更有意义的一种,如果偶尔发现一个瓶颈,可能会有所不同,将其拔出并timeit两种版本,然后查看。


首先,有些操作针对这两种类型进行了不同的优化。当然,这对于不同的实现甚至是同一实现的不同版本来说都是不同的,但是来自CPython 3.7的一些示例:

  • 对元组列表进行排序时,有一个特殊的unsafe_tuple_compare不适用于列表。
  • 在比较两个==!=的列表时,有一个特殊的is测试可以使比较短路,这有时会加快速度,但会减慢速度。小。对一堆完整的代码进行基准测试表明,这对于列表是值得的,但对于元组则不值得。

对于这些选择,通用性通常不会纳入其中;更多有关这两种类型通常如何使用的信息(列表通常是同类型的,但长度是任意的,而元组通常是异类的,并且长度是一致的)。但是,这并不是无关紧要的,例如,可以使列表包含自身(因为它们是可变的)而元组不能(因为它们不是)这样的事实至少可以防止应用于列表的一项次要优化。 2


第二,可以将同一编译单元中的两个相等的元组常量合并为相同的值。至少CPython和PyPy通常这样做。这样可以加快某些工作的速度(如果没有其他事情,当要缓存的数据较少时,您会获得更好的缓存位置,但是有时这意味着可以节省更多的钱,例如能够使用is测试)。

是关于可变性的:仅当编译器知道它们相等时,才允许它们合并相等的值。


第三,相同大小的列表更大。分配更多的内存,使用更多的缓存行等会稍微降低速度。

这也是关于可变性。清单最后必须有增长的空间。否则,呼叫append N次将花费N**2时间。但是元组不必append


1。在某些类型的问题中,很少有案例经常出现,以至于某些始终处理这些问题的人不断学习并记住它们。有时,您会在Stack Overflow上的一个优化问题上看到一个答案,有人听到“这用元组而不是列表可能会快3%”,而且他们通常是正确的。 < / p>

2。此外,我可以想象这样一种情况,一个JIT编译器(如PyPy中的JIT编译器)可以通过元组更好地加快速度。如果您以相同的值连续运行一百万次相同的代码,那么除非值发生变化,否则您将获得一百万个相同答案的副本。如果该值是两个对象的元组,则PyPy可以添加防护以查看这些对象中的任何一个是否发生更改,否则只需重用最后一个值即可。如果这是两个对象的列表,则PyPy必须向两个对象和该列表添加防护,这会使检查增加50%。是否真的发生,我不知道。每次我尝试跟踪PyPy优化的工作原理并从那里进行概括时,我发现都是错误的,最后我得出的结论是Armin Rigo是向导。