`namedtuple`在内存使用方面与元组一样高效吗?我的测试说没有

Amm*_*sfi 14 python memory collections tuples namedtuple

Python文档中指出,其优点之一namedtuple是它与元组一样具有内存效率.

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

测试表明:

  • 10000000namedtuple使用850 MiBRAM的实例
  • 10000000 tuple73 MiBRAM 周围使用的实例
  • 10000000 dict570 MiBRAM 周围使用的实例

所以namedtuple使用了更多的内存tuple!甚至dict!

你怎么看?我哪里做错了?

Bil*_*lly 20

更简单的指标是检查等效项tuplenamedtuple对象的大小.鉴于两个大致类似的对象:

from collections import namedtuple
import sys

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

point2 = (1, 2, 3)
Run Code Online (Sandbox Code Playgroud)

在内存中获取它们的大小:

>>> sys.getsizeof(point1)
72

>>> sys.getsizeof(point2)
72
Run Code Online (Sandbox Code Playgroud)

他们看起来和我一样......


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

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

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

在另一方面,你的列表namedtuple对象实际上确实创造千万唯一对象.

更好的苹果对苹果比较将是查看内存使用情况

>>> test_list = [(i, i+1, i+2) for i in range(10000000)]
Run Code Online (Sandbox Code Playgroud)

和:

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

它们的大小相同:

>>> sys.getsizeof(test_list)
81528056

>>> sys.getsizeof(test_list_n)
81528056
Run Code Online (Sandbox Code Playgroud)

  • 那是因为您总是只计算生成器对象的大小而不是结果数据结构 (2认同)

Jan*_*ina 6

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

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

  2. 基本类型的大小是:

    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

  3. 命名元组的时机非常糟糕:元组
    列表:1.8s
    命名元组
    列表:10s dicts 列表:4.6s

  4. 看着系统负载,我对 getsizeof 的结果产生了怀疑。在测量 Ptyhon3 进程的足迹后,我得到:

    test_list = [(i, i+1, i+2) for i in range(10000000)]
    增加:1 745 564K
    ,即每个元素约 175B

    test_list_n = [point(x=i, y=i+1, z=i+2) for i in range(10000000)]
    增加:1 830 740K
    ,即每个元素约 183B

    test_list_n = [point(x=i, y=i+1, z=i+2) for i in range(10000000)]
    增加:2 717 492 K
    ,即每个元素约 272B