显然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相关问答推荐

为什么我必须在绘制椭圆时代码等于两次?''

我不能使用拆分来分隔数据

如何强调您正在寻求以 pandas 数据帧的另一列为条件的差异?

基于Pandas列动态创建分箱,以使观测值数量或计数占总计数的1%.

如何在 20 秒后重复使用 Pillow 在现有图像上创建新图像?

当我判断另一个 checkButton 时,如何判断两个 python tkinter checkButtons?

在 Django 中执行 JSONRenderer.render(serialized_student_data.data) 时遇到问题

如何准确测定cv2的结果.在BW/黑白图像中查找对象?

删除重复项,但将值相加为一

在气流中运行 DAG 时出现处理信号:ttou消息

为什么 setattr 在绑定方法上失败

无法在 Windows Python 3.5 上安装 Levenshtein 距离包

pythondecorator中的变量范围

pysftp vs. Paramiko

if 语句中冒号的语法错误

Tensorflow:ImportError:libcudnn.so.7:无法打开共享对象文件:没有这样的文件或目录

作为函数对象属性的 __kwdefaults__ 有什么用?

PIL 在图像上绘制半透明方形覆盖

根据条件过滤元组列表

try 在 Mac OS 中运行此命令pipenv install requests时出错