【问题标题】:why python list size is different in below 2 cases [duplicate]为什么python列表大小在以下2种情况下不同[重复]
【发布时间】:2020-04-27 16:53:43
【问题描述】:

两个列表都有 3 个元素,但为什么列表大小不同?谢谢!

l1.append(1)
l1.append(2)
l1.append(3)
print(l1.__sizeof__()) # the size is 72

l2 = [1,2,3]
print(l2.__sizeof__()) # the size is 64

【问题讨论】:

  • 可能是因为在文字的情况下,底层缓冲区是精确分配的。当附加一个 python 列表时,它有时会过度分配以提供摊销的常数时间附加。不过,这真的没关系。这些是实现细节。

标签: python list


【解决方案1】:

l1.__sizeof__() 是 72,但在附加另一个元素后它仍然是 72。

l1.append(4)
print(l1.__sizeof__()) # prints 72 again

所以看来appending 第一次可能分配了太多空间,并且会用额外的appends 用完该空间。

l1 = []
print(l1.__sizeof__())  # prints 40
l1.append(1)
print(l1.__sizeof__())  # prints 72

4 个元素 - 仍然打印 72
5 个元素 - 打印 104

因此,72 - 40 = 32(假设列表对象有 40 个字节的开销)
32/4 = 8(4 个整数的非开销空间)
每个元素 8 个字节。似乎适合 64 位机器。

将其应用于字面定义的列表:

包含 3 个大小为 64 的元素的列表。

64 - 40 = 24 # 从列表大小中移除固定开销大小

24 / 8 = 3 # 剩余空间除以整数大小

我们正好得到 3 个元素。

是的,字面定义的列表被分配了它所需的确切空间量。

【讨论】:

    【解决方案2】:
    import time
    
    lyst = []
    while True:
        print(len(lyst), (lyst.__sizeof__() - 40) // 8)  # 40 bytes for empty list, 8 bytes per element
        lyst.append(1)
        time.sleep(.05)  # don't go too fast
    

    会输出

    0 0
    1 4
    2 4
    3 4
    4 4
    5 8
    6 8
    7 8
    8 8
    9 16
    10 16
    11 16
    12 16
    13 16
    14 16
    15 16
    16 16
    17 25
    

    等等:

    当您追加到一个没有足够内存来存储元素的列表时,它需要重新调整大小。调整大小是昂贵的(linear time 复杂性),如果你只是追加到一个列表,你很有可能会再次追加,所以我们希望避免不断地调整列表的大小。因此,与其将其大小调整为足够大以适合您要附加的元素,不如将列表的大小调整为其已经大小的某个百分比,以使附加一个恒定的时间操作。随着列表变大,您仍然需要不时遍历整个列表来复制它,但列表越大,这种情况就越少。

    而声明一个列表文字 l = [1, 2, 3] 会准确分配保存该大小的列表所需的内存量。

    https://en.wikipedia.org/wiki/Dynamic_array#Geometric_expansion_and_amortized_cost

    这是在 CPython 中的 listobject.c 中实现的

    【讨论】:

    • 不错的图表,@Boris 你是怎么做到的?
    • 一旦你从他的算法中得到了 x 和 y,你可以从该数据中创建一条线并添加另一条线性 y~x 的线。 Python 有用于绘图的 matplotlib 库,不过我更喜欢 ggplotr。无论如何,他的插图非常好,几周前我刚刚在 python 中学习了这种行为。
    • 要查看dict 的类似图表,请查看Dictionary size reduces upon increasing one element
    猜你喜欢
    • 2012-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-07
    • 2014-08-22
    • 2015-11-27
    相关资源
    最近更新 更多