显然list(a)没有超额分配,[x for x in a]在某些点超额分配,[*a]超额分配all the time

Sizes up to n=100

以下是从0到12的大小n,以及三种方法的结果大小(以字节为单位):

0 56 56 56
1 64 88 88
2 72 88 96
3 80 88 104
4 88 88 112
5 96 120 120
6 104 120 128
7 112 120 136
8 120 120 152
9 128 184 184
10 136 184 192
11 144 184 200
12 152 184 208

使用Python 3.8计算如下,reproducable at repl.it:

from sys import getsizeof

for n in range(13):
    a = [None] * n
    print(n, getsizeof(list(a)),
             getsizeof([x for x in a]),
             getsizeof([*a]))

So: How does this work?.[*a]美元如何超额分配?实际上,它使用什么机制从给定的输入创建结果列表?它是否在a上使用迭代器,并使用类似于list.append的东西?源代码在哪里?

(产生这些图像的Colab with data and code人.)

放大到更小的n:

Sizes up to n=40

缩小到更大的n:

Sizes up to n=1000

推荐答案

[*a] is internally doing the C equivalent of:

  1. 做一个新的,空的list
  2. newlist.extend(a)
  3. 返回list.

因此,如果您将测试扩展到:

from sys import getsizeof

for n in range(13):
    a = [None] * n
    l = []
    l.extend(a)
    print(n, getsizeof(list(a)),
             getsizeof([x for x in a]),
             getsizeof([*a]),
             getsizeof(l))

Try it online!

你会看到getsizeof([*a])l = []; l.extend(a); getsizeof(l)的结果是一样的.

这通常是正确的做法;当进行extend次打包时,您通常希望以后添加更多内容,而对于一般化的解包,则假定会一个接一个地添加多个内容.[*a]不是正常情况;Python假定list([*a, b, c, *d])中添加了多个项或可重用项,因此在常见情况下,过度分配可以节省工作.

相比之下,一个list由一个单一的、预先确定尺寸的可植入物(list())构成,在使用过程中可能不会增长或收缩,而且过度分配是不成熟的,除非另有证明;Python recently fixed a bug that made the constructor overallocate even for inputs with known size

至于list个理解,它们实际上相当于重复的append个,所以当一次添加一个元素时,你会看到正常的过度分配增长模式的最终结果.

明确地说,这些都不是语言保证.这就是CPython实现它的方式.Python语言规范通常不关心list中的特定增长模式(除了保证从末尾开始摊销O(1)appendpop).如 comments 中所述,具体实施在3.9中再次发生变化;虽然它不会影响[*a],但它可能会影响其他情况,即过go "构建单个项目的临时tuple,然后用tuple构建extend"现在变成了LIST_APPEND的多个应用程序,当出现超额分配时,以及计算中的数字时,这些应用程序可能会发生变化.

Python-3.x相关问答推荐

安装grpcio时出现错误DeproationWarning:pkg_resource

谁能解释一下这个带邮编的多功能环路?

Django 3.2/Django-cms 3.11:查找错误:型号帐户.客户用户未注册

无法使用xpath关闭selenium中的弹出窗口

我无法直接在 VSCode 中运行该程序,但可以使用 VScode 中的终端运行它

在不改变 python 中原始数组顺序的情况下,对多维字符串数组进行降序排序?

pytorch 中 mps 设备的 manual_seed

在 python pandas 中设置条件和分配新值

根据另一个数据帧中的位置从主数据帧中提取子序列

matplotlib.pyplot 多边形,具有相同的纵横比和紧凑的布局

用于 BIG 数组计算的多处理池映射比预期的要慢

Dask 多阶段资源设置导致 Failed to Serialize 错误

Python rolling_corr 取消后,应该用什么方法来处理

使用 python-binance 时,heroku [regex._regex_core.error: bad escape \d at position 7] 出错

在python中循环处理时并行写入文件

判断是否存在大文件而不下载它

sys.stdin.readline() 和 input():读取输入行时哪个更快,为什么?

Python3 - 如何从现有抽象类定义抽象子类?

如何使用 python http.server 运行 CGI hello world

注册 Celery 基于类的任务