【问题标题】:Python efficiency: lists vs. tuplesPython 效率:列表与元组
【发布时间】:2011-08-29 03:23:47
【问题描述】:

我有中等数量的基础对象。

这些基础对象将被放入集合中,并且这些集合将被修改:排序、截断等。

不幸的是,n 足够大,以至于内存消耗有点令人担忧,而且速度也越来越令人担忧。

我的理解是元组的内存效率稍高一些,因为它们被删除了重复数据。

无论如何,我想知道 Python 2.6/2.7 中列表与元组的 cpu/内存权衡是什么。

【问题讨论】:

  • 什么是中等数量?你有没有分析过你的代码?告诉我们你的瓶颈在哪里。

标签: python python-2.7 optimization python-2.6


【解决方案1】:

如果您有一个元组和一个具有相同元素的列表,则元组占用的空间更少。由于元组是不可变的,因此您无法对其进行排序、添加等操作。我建议您观看this talk by Alex Gaynor,以快速了解何时在 Python 中选择何种数据结构。

更新:再想一想,您可能需要考虑优化对象的空间使用,例如,通过__slots__ 或使用namedtuple 实例作为代理而不是实际对象。这可能会带来更大的节省,因为您拥有其中 N 个并且(大概)只有少数几个集合出现它们。 namedtuple 特别棒;查看Raymond Hettinger's talk

【讨论】:

    【解决方案2】:

    正如其他人提到的,元组是不可变的。对元组进行排序(例如sorted(mytuple))会返回一个列表,然后您必须将其转换回一个元组。

    要对元组进行排序(并将其保留为元组),您必须这样做:

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

    要对列表进行排序,您必须这样做:

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

    因为你不是在铸造和重新铸造,在这种情况下,后者更有效。

    除非您有充分的理由,否则不要纠结于在列表上使用元组。如果您需要已排序的数据,元组不是要走的路,除非它们首先以这种方式创建。当元组包含的数据不变时,例如在运行时加载的配置设置或已经处理的数据,元组表现出色。

    考虑到您提到您正在处理一个大型数据集,您可能希望通过列表和元组上的生成器和迭代器来使用函数式编程风格。这样,您就不会四处奔波并创建新容器,而只是链接迭代操作以获得最终结果。

    进一步阅读:

    【讨论】:

    • 我正在大量收集对象。对象本身会发生变化。在大多数情况下,这些集合正在被过滤和映射。其中许多集合可能包含相同的对象(实际上是对对象的引用)。我正在考虑使用 tuples 作为减少内存使用的机制。
    • 我和你在一起!从字面上看:我的建议是,不要使用filtermap (返回列表),而是使用每个等效的itertools:itertools.ifilteritertools.imap,它们返回迭代器。如果你一直这样做,那么你可以使最终结果成为一个元组。如果可能的话,即使是被过滤/映射的初始集合也可以并且应该是迭代器而不是列表/元组。这样一来,您只有在拥有真正想要的东西后才生成一个新集合。
    • @PaulNathan 在您上面的评论中,您的意思是“对象本身不会 改变”吗?正在阅读有关不可变对象的交流,并以为我在关注它,直到那句话把我扔了。感谢大家进行这个非常有教育意义的讨论!
    【解决方案3】:

    集合中基础对象的(平均、最小、最大)数量是多少?

    元组被“去重”而列表不是?在这种情况下,您认为“去重”是什么意思?

    列表确实比元组占用更多的内存,因为额外的内存是在假设列表会增长的情况下分配的,而且您肯定不想在每次执行 large_list.append() 时都重新分配内存。但是在 32 位机器上,额外列表元素的摊销成本是 4 字节的指针,N 字节的元素本身,不超过另外 4 字节的额外内存。 N 是浮点数的 16 个字节。这意味着浮点数列表每个额外的浮点数最多占用 24 个字节,而元组则需要 20 个字节。 N==100 的“基础对象”给出 108 与 104 的比较。如果在两个集合中引用基础对象,则为 58 与 54。您的 N 有多大?

    建议:将您的收藏保留为列表。专注于:

    • 确保您的基础对象具有内存效率

    • 尽可能使用生成器和 itertools 工具而不是临时列表

    • 如果您无法避免临时列表,请确保立即将它们丢弃,不再需要它们,即不要等到创建方法返回;尽快使用明确的del

    【讨论】:

      【解决方案4】:

      除了所有这些建议之外,您可能会发现numpy 将满足您的需求。如果您的对象是 numpy 默认处理的对象(整数、本机 C 类型等),那么这将是理想的。您也可以将 numpy 数组与自定义对象一起使用,但这可能比它的价值更多。

      【讨论】:

        【解决方案5】:

        您不能以同样的方式使用它们。元组是不可变的,不支持追加、排序等(在元组上调用sorted 会产生一个列表,等等)。元组与列表完全不同,因此任何性能比较都是没有意义的。

        【讨论】:

        • 让我们想象一下它们都被用作容器,对随机数的索引进行排序,好吗?
        • @Paul 我不明白你在说什么。这将如何影响元组无法按照您想要的方式操作的事实。
        • 让我们假设可以重写算法以应对不变性。有了这个假设,让我们继续分析 Python 列表与元组的效率。
        • @Paul 在这种情况下,没有可比性。这就像将集合与字典进行比较;没有意义。但是,我可以说元组不打算以这种方式使用。
        • @Paul 元组没有顺序,它们是结构化的。它们的行为根本不像列表,也不用于完成相同的事情。您需要寻找一种方法来将数据存储在内存之外,而不是尝试使用无法满足您的需求的数据结构,
        【解决方案6】:

        您无法对不可变对象进行排序 - 即,在对元组进行排序时,您总是会创建一个新对象。

        【讨论】:

          【解决方案7】:

          至少有两个现有问题与您的问题足够相似,因此答案(或其中的链接)可能对您有用。总结一下:让类型的特征(可变与不可变,异构与同质)而不是性能来指导您的决策,因为性能/效率差异很小。

          What's the difference between list and tuples in Python?
          What are differences between List, Dictionary and Tuple in Python?

          【讨论】:

            猜你喜欢
            • 2012-09-14
            • 2012-07-09
            • 2012-08-18
            • 2013-08-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-10-31
            相关资源
            最近更新 更多