What is a Python list underneath?
A dynamic array of references — one contiguous block of pointers, over-allocated so there is usually spare room. Indexing is O(1) because the address is computed. append is amortised O(1) because it usually writes into a spare slot. insert(0, x) is O(n) because everything has to shift.
Overview
An array of pointers, not of objects
The block holds references, all the same size, which is why one list can hold an int, a string and another list at once. It is also why sys.getsizeof on a list of a million integers is far smaller than the integers themselves — the list only stores the pointers.
Because the references are contiguous and equally sized, element i lives at a computable address. That is the whole reason indexing is O(1) and a linked list is not.
Step through it
What to watch
- The spare slots are the reason
appendis normally free. - The reallocation copies everything — once per doubling, not per append.
- The last frame is the same cost as
pop(0), in the other direction.
Say this out loud
"It's a dynamic array of pointers, over-allocated. Indexing is O(1) arithmetic, append is amortised O(1) because growth doubles, and anything that touches the front is O(n) because the rest has to shift."