I recently had a discussion about what the Python interpreter is actually doing when you multiply an array with an integer, e.g. [1] * 3. Someone suggested that Python will generate 3 copies of [1] in memory and then concatenate those copies. A more efficient solution would be a list comprehension (e.g. [1 for _ in range(3)]), which would avoid all this overhead.
That sounds pretty logical, but then I decided to compare the runtime of both methods
>>> timeit.timeit('[1] * 1000000', number=100)
0.6567943999999954
>>> timeit.timeit('[1 for _ in range(1000000)]', number=100)
6.787221699999975
(Python 3.9.7 on Windows)
Looks like the array multiplication method is an order of magnitude faster than the list comprehension.
I wanted to understand what's going on under the hood, so I tried to disassemble the function:
>>> def array_multiply():
... return [1] * 3
...
>>> import dis
>>> dis.dis(array_multiply)
2 0 LOAD_CONST 1 (1)
2 BUILD_LIST 1
4 LOAD_CONST 2 (3)
6 BINARY_MULTIPLY
8 RETURN_VALUE
Well, that wasn't helpful. It just says BINARY_MULTIPLY, but not what's happening when you multiply a list and an integer.
Is there a way to go one level deeper? See the C code that handles [1] * 3, or inspect the machine code Python is producing when I execute this function?