Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python “namedtuple”在内存使用方面真的和元组一样高效吗?我的测试结果是否定的_Python_Memory_Collections_Tuples_Namedtuple - Fatal编程技术网

Python “namedtuple”在内存使用方面真的和元组一样高效吗?我的测试结果是否定的

Python “namedtuple”在内存使用方面真的和元组一样高效吗?我的测试结果是否定的,python,memory,collections,tuples,namedtuple,Python,Memory,Collections,Tuples,Namedtuple,Python文档中指出,namedtuple的优点之一是它与元组一样具有内存效率 为了验证这一点,我使用iPython和。测试如下图所示: 试验表明: 10000000namedtuple的实例用于RAM的850 MiB 10000000tuple在RAM的73 MiB周围使用的实例 10000000dict在RAM的570 MiB周围使用的实例 所以namedtuple使用的内存比tuple多得多!甚至比dict更多 你觉得怎么样?哪里出错了?一个更简单的度量是检查等价的元组和命名元组

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

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

试验表明:

  • 10000000
    namedtuple的实例用于RAM的
    850 MiB
  • 10000000
    tuple
    在RAM的
    73 MiB
    周围使用的实例
  • 10000000
    dict
    在RAM的
    570 MiB
    周围使用的实例
所以
namedtuple
使用的内存比
tuple
多得多!甚至比dict更多


你觉得怎么样?哪里出错了?

一个更简单的度量是检查等价的
元组
命名元组
对象的大小。给定两个大致相似的对象:

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个引用

另一方面,您的
namedtuple
对象列表实际上创建了10000000个唯一的对象

一个更好的苹果对苹果的比较是查看

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

它们大小相同:

>>> sys.getsizeof(test_list)
81528056

>>> sys.getsizeof(test_list_n)
81528056

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

  • 在所有三种情况下(元组列表、命名元组列表、dict列表)。sys.getsizeof返回列表的大小,该列表只存储引用。这三种情况下的尺寸都是81528056

  • 基本类型的大小为:

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

    sys.getsizeof(点(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]

    增加:1745564K
    即每个元素大约175B

    test\u list\u n=[范围(10000000)内i的点(x=i,y=i+1,z=i+2)]

    增加:1830740K
    即每个元素大约183B

    test\u list\u n=[范围(10000000)内i的点(x=i,y=i+1,z=i+2)]

    增加:2717492 K
    这大约是每个元素272亿


  • 我对您的问题没有明确的答案,但窥视孔优化器可能注意到您的元组被定义为具有不可变成员的文本,并向您返回了对同一元组的引用列表。@Chinny84--实际上,我很惊讶字典占用的内存比命名元组少。我知道如果您使用的是python3.6,字典已经升级为一个新的实现,它应该更节省内存,但我仍然认为这不应该超过元组…@mgilson这可能是因为
    namedtuple()
    返回的类具有一些Python级别的属性,另一方面,
    dict
    仍然是纯C语言。就像mgilson提到的那样,尝试动态创建元组。CPython可以缓存不可变对象的文本,不幸的是namedtuple没有文本,因此无法缓存。@mgilson:快速检查表明您的假设是正确的。
    (1,2,3)
    的构造被常数折叠,循环中的所有
    append
    调用都附加相同的元组。有趣的是,它与字典大小相同:>>>test_list_d=[{“x”:i,“y”:i+1,“z”:i+2}对于范围(10000000)]>>中的i,sys.getsizeof(test_list_d)81528056这是因为您总是只计算生成器对象的大小,而不是结果数据结构
    >>> sys.getsizeof(test_list)
    81528056
    
    >>> sys.getsizeof(test_list_n)
    81528056