Despite Python’s desire to have only one way to achieve the same thing, even such a trivial matter as creating a new list instance can be done in many different ways, including usage of list literals, list multiplication and list comprehensions
Bytecode instructions immediately reveal that using array comprehensions is unlikely to be performant
but list literal and list multiplication approach look much shorter
So let’s take these approaches for a spin
As expected, list comprehension performed significantly worse than other contenders. Using list literals has the lowest runtime and list multiplication is almost 2X slower than it.
Unfortunately using list literals doesn’t scale very well - it’s no fun to type or generate list literals with thousands of elements, is it? But before we give up on list multiplication, let’s get back to the title of the article - memory usage.
Ouch, looks like lists created using list literals take much more memory than list multiplication. We can infer the reason by looking at how memory usage changes with increasing the number of elements
Looks like we use list extend under the hood when creating lists using list literals but for list multiplication we know the size in advance and allocate the exact amount of needed memory. Python’s source code confirms that - CPython is using list_preallocate_exact in case list instance is created from an iterable with a known size.
But still, why do we need entire 80 bytes to store a list of 3 elements? To avoid boring you with unnecessary details, I’ll just leave a link to a PyListObject source code that reveals list structure and fields like allocated, ob_item and other common Python object header fields.
So what’s the conclusion? List multiplication is a fairly fast and most memory efficient way to create list instances.