【发布时间】:2019-09-12 01:05:19
【问题描述】:
我读过 python 列表应该占用 64 个字节,并且列表中的每个条目都应该“花费”8 个额外的字节。我决定测试一下。但是,在测试时,我发现这取决于您如何将项目添加到列表中。为什么下面代码中ob1和obj2的sys.getsizeof不一致?
import sys
test1 = 'This is a string.'
obj1 = []
obj2 = ['T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 's', 't', 'r', 'i', 'n', 'g', '.']
obj3 = list(test1)
for i in range(len(test1)):
obj1.append(test1[i])
print(sys.getsizeof(obj1))
print(obj1)
print(sys.getsizeof(obj2))
print(obj2)
print(sys.getsizeof(obj3))
print(obj3)
>>>264
>>>['T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 's', 't', 'r', 'i', 'n', 'g', '.']
>>>200
>>>['T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 's', 't', 'r', 'i', 'n', 'g', '.']
>>>264
>>>['T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 's', 't', 'r', 'i', 'n', 'g', '.']
obj2 报告我预期的大小 (64+8*17=200)。使用append-function 后的开销是多少,在构造列表后能否以某种方式消除开销?
我已经阅读了这个相关主题here,但我认为他们的答案与另一个似乎与 Pandas 相关的答案不同。
【问题讨论】:
-
因为当您使用列表文字时,Python 知道 exact 大小。如果您使用
.append,它会在重新调整大小时变得过大。更重要的是,你为什么关心?这个开销是一个无穷小部分,它可以让你摊销固定时间附加,这太棒了。 -
几乎可以肯定,这是一个副本:stackoverflow.com/questions/51526242/…,尽管它并不完全相同。在那个例子中,当您使用
some_list * some_int时会看到这种行为,这是解释器在运行时可以准确知道结果列表大小的另一个示例。但是,与您的列表文字情况相同,挖掘该源代码会很烦人。但是如果你dis.dis是一个列表文字表达式,你会看到BUILD_LIST操作码 -
我关心,因为我打算使用该值来计算压缩率。我需要知道差异来自哪里,这样我才能正确解释它。而且我认为这不是更重要的事情,我的意思是为什么我在乎。这本身就是一个有趣的问题。但是谢谢你的链接,奇怪的是我的任何搜索都没有弹出它。
-
您应该非常警惕使用
sys.getsizeof处理这类事情。请注意,它 仅 为您提供缓冲区的大小 + python 对象开销,缓冲区将是 PyObject* 数组的大小乘以系统上的 PyObject 指针(通常是机器字)。此外,通读这两个问题,您会发现底层缓冲区的增长方式可能会因各种因素而略有不同。你应该考虑改变你的方法。你在压缩什么? -
那么您应该使用
str,或者更好的是bytes对象。bytes是专门为这类事情而设计的,并且可以更可预测地扩展。我实际上不确定bytearray,这可能真的是最好的。bytearray可能会过度分配,但也许不会?在任何一种情况下,如果您从bytearray创建bytes,它应该为您提供确切的大小+一些恒定的开销,比list对象更可靠。听起来很有趣:)
标签: python list memory python-3.7