I think you see redistribution patterns, this is a sample from the source :
new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
Listing the sizes of lists containing lengths of 0-88, you can see the pattern matching:
Results (format (list length, (old total size, new total size)) ):
(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))
Redistribution is performed for performance reasons, which allows you to create lists without allocating more memory with each growth (better amortized ).
The likely reason for the difference in using list comprehension is that list comprehension cannot deterministically calculate the size of the generated list, but list() can. This means that understanding will constantly increase the list as it fills it using redundant distribution until it is finally filled.
It is possible that this will not increase the redistribution buffer with unused allocated nodes after its execution (in fact, in most cases it will not, which will lead to the defeat of the redistribution target).
list() , however, can add some buffer regardless of the size of the list, since it knows in advance the size of the final list.
Another supporting evidence, also from the source, is that we see lists calling LIST_APPEND , which indicates the use of list.resize , which, in turn, indicates the consumption of the pre-allocation buffer, not knowing how much of it will be populated . This is consistent with the behavior you see.
In conclusion, list() will pre-allocate more nodes as a function of list size
>>> sys.getsizeof(list([1,2,3])) 60 >>> sys.getsizeof(list([1,2,3,4])) 64
Understanding the list does not know the size of the list, so it uses the add operations when it grows, draining the pre-allocation buffer:
# 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