提问者:小点点

“命名元组”在内存使用方面真的和元组一样高效吗?我的测试说不


在 Python 文档中指出,命名元组的优点之一是它与元组一样具有内存效率。

为了验证这一点,我将iPython与ipython_memory_usage一起使用。测试如下图所示:

测试表明:

  • 10000000命名元组实例使用了大约 850 MiB 的 RAM
  • 10000000 个元组实例使用了大约 73 MiB 的 RAM
  • 10000000字典实例使用了大约 570 MiB 的 RAM

所以命名元组组使用更多的内存!甚至比字典还要多!!

你觉得怎么样?我哪里做错了?


共2个答案

匿名用户

更简单的指标是检查等效元组和命名元组对象的大小。给定两个大致相似的对象:

from collections import namedtuple
import sys

point = namedtuple('point', 'x y z')
point1 = point(1, 2, 3)

point2 = (1, 2, 3)

获取内存中它们的大小:

>>> sys.getsizeof(point1)
72

>>> sys.getsizeof(point2)
72

对我来说,它们看起来是一样的...

进一步复制结果,请注意,如果您按照自己的方式创建相同元组的列表,则每个元组都是完全相同的对象:

>>> test_list = [(1,2,3) for _ in range(10000000)]
>>> test_list[0] is test_list[-1]
True

因此,在元组列表中,每个索引都包含对同一对象的引用。没有 10000000 个元组,对一个元组有 10000000 个引用。

另一方面,您的命名元组对象列表实际上确实创建了 10000000 个唯一对象。

更好的同类比较是查看内存使用情况

>>> test_list = [(i, i+1, i+2) for i in range(10000000)]

和:

>>> test_list_n = [point(x=i, y=i+1, z=i+2) for i in range(10000000)]

它们具有相同的大小:

>>> sys.getsizeof(test_list)
81528056

>>> sys.getsizeof(test_list_n)
81528056

匿名用户

自己做一些调查(使用Python 3.6.6)。我得出以下结论:

>

  • 在所有三种情况下(元组列表、命名元组列表、字典列表).sys.getsizeof 返回列表的大小,无论如何它只存储引用。所以你会得到尺寸:在所有三种情况下都是81528056。

    基本类型的尺寸为:

    sys.getsizeof((1,2,3)) 72

    sys.getsizeof(point(x=1, y=2, z=3)) 72

    sys.getsizeof(dict(x=1, y=2, z=3)) 240

    命名元组的时机非常糟糕: 元组列表:
    1.8s
    命名元组列表:10s
    字典列表:4.6s

    查看系统负载,我对getsizeof的结果产生了怀疑。在测量了Ptyhon3工艺的足迹后,我得到:

    test_list = [(i, i 1, i 2) 对于范围 (10000000)] 中的 i 增加
    :1 745 564K
    ,即每个元素约 175B

    test_list_n = [点(x=i, y=i 1, z=i 2) 对于范围(10000000)中的 i]
    增加:1 830 740K
    ,即每个元素约 183B

    test_list_n = [点(x=i, y=i 1, z=i 2) 对于范围 (10000000)] 中的 i 增加
    :2 717 492 K
    ,即每个元素约 272B