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