这句话是否与python范式相矛盾;列表不应初始化";?

这句话是否与python范式相矛盾;列表不应初始化";?,python,Python,来自其他python编码语言的人经常会问,他们应该如何预分配或初始化列表。对于来自Matlab的人来说尤其如此,因为Matlab中的代码 l = [] for i = 1:100 l(end+1) = 1; end 返回一条警告,明确建议您初始化列表 有几篇文章解释(并通过测试展示)python中不需要列表初始化。这是一个很好的例子,有相当多的讨论(但列表可能很长): 然而,前几天,当我在python中寻找操作复杂性时,我无意中发现了这句话: 最大的[列表操作成本]来自超出当前分配规模

来自其他python编码语言的人经常会问,他们应该如何预分配或初始化列表。对于来自Matlab的人来说尤其如此,因为Matlab中的代码

l = []
for i = 1:100
    l(end+1) = 1;
end
返回一条警告,明确建议您初始化列表

有几篇文章解释(并通过测试展示)python中不需要列表初始化。这是一个很好的例子,有相当多的讨论(但列表可能很长):

然而,前几天,当我在python中寻找操作复杂性时,我无意中发现了这句话:

最大的[列表操作成本]来自超出当前分配规模的增长(因为所有东西都必须移动)

这似乎表明,实际上列表确实有一个预分配大小,并且超过该大小会导致整个列表移动

这有点动摇了我的基础。列表预分配是否可以降低代码的总体复杂性(以操作数量而言)?如果不是,那句话是什么意思

编辑:

显然,我的问题涉及(非常常见的)代码:

在这种情况下,编译器无法知道
容器中有多少项
,因此
新列表
可能会要求其分配的内存更改难以置信的次数,如果该句子中所说的是真的

我知道这与列表理解不同

列表预分配是否可以降低代码的总体复杂性(以操作数量而言)

不,代码的总体时间复杂度将是相同的,因为当摊销所有增加列表大小的操作时,重新分配列表的时间成本为O(1)

如果不是,那句话是什么意思

原则上,通过避免多次重新分配,预先分配列表可以通过一些固定因素减少运行时间。这并不意味着复杂性更低,但可能意味着代码在实践中更快。如果有疑问,请对代码的相关部分进行基准测试或分析,以比较这两个选项;在大多数情况下,这并不重要,当它发生时,可能会有更好的替代方案(例如NumPy阵列)来实现相同的目标

new_list
可能需要他分配的内存更改难以置信的次数

列表重新分配遵循a,因此,如果列表的最终长度为n,则该列表沿途仅重新分配O(logN)次;不是“难以置信的次数”。数学计算的方式是,每个元素被复制到新的基础数组的平均次数是一个常数,而不管列表有多大,因此添加到列表的O(1)摊销成本是不变的

列表预分配是否可以降低代码的总体复杂性(以操作数量而言)

不,代码的总体时间复杂度将是相同的,因为当摊销所有增加列表大小的操作时,重新分配列表的时间成本为O(1)

如果不是,那句话是什么意思

原则上,通过避免多次重新分配,预先分配列表可以通过一些固定因素减少运行时间。这并不意味着复杂性更低,但可能意味着代码在实践中更快。如果有疑问,请对代码的相关部分进行基准测试或分析,以比较这两个选项;在大多数情况下,这并不重要,当它发生时,可能会有更好的替代方案(例如NumPy阵列)来实现相同的目标

new_list
可能需要他分配的内存更改难以置信的次数


列表重新分配遵循a,因此,如果列表的最终长度为n,则该列表沿途仅重新分配O(logN)次;不是“难以置信的次数”。数学计算的结果是,每个元素被复制到新的基础数组的平均次数是一个常数,不管列表有多大,因此添加到列表的O(1)摊销成本。

这句话说,超出当前分配的增长是列表最重的操作。它并没有说它太重,或者建议预先分配。当对你的具体案例有疑问时进行基准测试。@deceze我知道我可以进行基准测试,但在这方面已经有太多基准测试了,我的基准测试将是沧海一粟。另外,在我发布的问题中,它显示了计时这件事是多么的棘手,因为看似无害的操作就像仅仅生成要附加的项可以屏蔽您想要测试的东西一样。老实说,我更多地是在寻找一个理论解释,而不仅仅是一个“看,它是有效的”。但问题依然存在:目前的分配是什么?如果增长超过它是沉重的,为什么总是不鼓励预先分配呢?python中的列表,因为它们是为了变异而构建的,有一些预先分配的内存,这允许像追加之类的操作更快。这就是为什么元组在内存中占用更少的空间。但是,如果您可以按照自己的喜好声明列表(即列表理解,或
[1]*1000
)@LucaAmerio,那么预分配对您没有任何好处-从您的评论来看,您似乎在尝试优化列表创建,然后才知道这是否是一个特定的问题。仅仅因为理论上更高效,就将自己锁定在创建列表的一种特定方式中,这会限制你使用它的某些模式。@二战I赞扬你的简洁性,但你能解释一下为什么上面这句话吗?这句话说,超出当前分配的增长是列表最繁重的操作。它并没有说它太重,或者建议预先分配。在您的具体案例有疑问时进行基准测试。@deceze我知道我可以
container = ... #some iterable with 1 gazilion elements
new_list = []
for x in container:
    ... #do whatever you want with x
    new_list.append(x) #or something computed using x