<p>我想你看到的是分配模式这是一个<a href="https://github.com/python/cpython/blob/3.5/Objects/listobject.c#L42" rel="noreferrer">sample from the source</a>:</p>
<pre class="lang-c prettyprint-override"><code>/* This over-allocates proportional to the list size, making room
* for additional growth. The over-allocation is mild, but is
* enough to give linear-time amortized behavior over a long
* sequence of appends() in the presence of a poorly-performing
* system realloc().
* The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
*/
new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
</code></pre>
<hr/>
<p>打印长度为0-88的列表理解的大小可以看到匹配的模式:</p>
^{pr2}$
<p>结果(格式为<code>(list length, (old total size, new total size))</code>):</p>
<pre><code>(0, (64, 96))
(4, (96, 128))
(8, (128, 192))
(16, (192, 264))
(25, (264, 344))
(35, (344, 432))
(46, (432, 528))
(58, (528, 640))
(72, (640, 768))
(88, (768, 912))
</code></pre>
<hr/>
<p>过度分配是出于性能原因而进行的,允许列表在每次增长时不分配更多内存(更好的<a href="https://en.wikipedia.org/wiki/Amortized_analysis" rel="noreferrer">amortized</a>性能)。在</p>
<p>与使用列表理解不同的一个可能原因是,列表理解不能确定地计算生成的列表的大小,但是<code>list()</code>可以。这意味着,在使用过度分配填充列表时,理解将不断增加列表,直到最终填充为止。在</p>
<p>一旦完成,is可能不会增加具有未使用的已分配节点的过度分配缓冲区(事实上,在大多数情况下,它不会,这将破坏过度分配的目的)。在</p>
<p>但是,<code>list()</code>可以添加一些缓冲区,不管列表大小如何,因为它预先知道最终的列表大小。在</p>
<hr/>
<p>另一个支持性证据(同样来自源代码)是,我们看到了<a href="https://github.com/python/cpython/blob/3.5/Python/compile.c#L3374" rel="noreferrer">list comprehensions invoking ^{<cd4>}</a>,它表示使用<code>list.resize</code>,而这又表示在不知道将填充多少预分配缓冲区的情况下使用它。这和你看到的行为是一致的。在</p>
<hr/>
<p>总之,<code>list()</code>将根据列表大小预先分配更多节点</p>
<pre><code>>>> sys.getsizeof(list([1,2,3]))
60
>>> sys.getsizeof(list([1,2,3,4]))
64
</code></pre>
<p>List comprehension不知道列表的大小,因此它在增长时使用append操作,耗尽预分配缓冲区:</p>
<pre><code># one item before filling pre-allocation buffer completely
>>> sys.getsizeof([i for i in [1,2,3]])
52
# fills pre-allocation buffer completely
# note that size did not change, we still have buffered unused nodes
>>> sys.getsizeof([i for i in [1,2,3,4]])
52
# grows pre-allocation buffer
>>> sys.getsizeof([i for i in [1,2,3,4,5]])
68
</code></pre>