Python效率:列表与元组

8 投票
7 回答
8367 浏览
提问于 2025-04-16 17:59

我有一堆基础对象。

这些基础对象会被放进一些集合里,然后这些集合会被处理,比如排序、截断等等。

可惜的是,这些对象的数量有点多,导致内存使用量让我有点担心,而且速度也开始变得令人担忧。

我了解到,元组在内存使用上稍微更有效,因为它们会去掉重复的部分。

总之,我想知道在Python 2.6/2.7中,列表和元组在CPU和内存方面的优缺点是什么。

7 个回答

4

一个集合里平均、最少和最多有多少个基本对象呢?

元组是“去重”的,而列表不是?你觉得这里的“去重”是什么意思呢?

列表占用的内存比元组多,因为列表在设计时就预留了额外的内存,以便于列表将来可能会增加元素。这样的话,每次用大列表添加元素时,就不需要重新分配内存了。不过在32位的机器上,增加一个列表元素的平均内存开销是4字节用于指针,N字节用于元素本身,另外最多再加4字节的额外内存。这里的N如果是16字节(比如一个浮点数),那么每增加一个浮点数,列表大约需要24字节,而元组只需要20字节。如果一个基本对象的N是100,那么列表和元组的比较就是108字节对104字节。如果一个基本对象在两个集合中都被引用,那么就是58字节对54字节。你的N有多大呢?

建议:保持你的集合为列表。重点关注:

  • 确保你的基本对象在内存上是高效的

  • 尽量使用生成器和itertools中的工具,而不是临时列表

  • 如果无法避免使用临时列表,确保在不再需要它们时立即删除,也就是说,不要等到创建方法返回时再删除;尽早使用del

9

正如其他人提到的,元组是不可变的。这意味着一旦创建了元组,就不能改变它的内容。如果你想对一个元组进行排序,比如用 sorted(mytuple),那么它会返回一个列表,你还得再把这个列表转回元组。

如果你想对一个元组进行排序并保持它是元组,你需要这样做:

mytuple = (3,2,1)
mysortedtuple = tuple(sorted(mytuple))

而如果你想对一个列表进行排序,你需要这样做:

mylist = [3,2,1]
mylist.sort()

因为在后面的例子中你没有进行转换,所以这样做更高效。

除非你有很好的理由,否则不要纠结于使用元组而不是列表。如果你需要排序的数据,元组并不是最佳选择,除非它们一开始就是以这种方式创建的。元组在数据不需要改变的情况下表现得很好,比如运行时加载的配置设置,或者已经处理过的数据。

考虑到你提到你正在处理一个大数据集,你可能想要考虑使用一种函数式编程的风格,使用生成器和迭代器,而不是列表和元组。这样你就不需要不断创建新的容器,而是通过链接迭代操作来达到最终结果。

进一步阅读:

16

如果你有一个元组和一个列表,它们的内容是一样的,元组占用的空间会更少。因为元组是不可改变的,所以你不能对它们进行排序、添加元素等操作。我建议你看看Alex Gaynor的这场演讲,里面简单介绍了在Python中什么时候选择什么数据结构。

更新:再想想,你可能想要考虑优化你对象的空间使用,比如通过__slots__,或者使用namedtuple实例作为代理,而不是使用实际的对象。这样做可能会节省更多空间,因为你有N个这样的对象,而(假设)只有少量的集合包含它们。特别是namedtuple非常棒;可以看看Raymond Hettinger的演讲

撰写回答