3 ms·
You can see the CPython list implementation here: https://hg.python.org/cpython/file/273e17260d25/Objects/listobject.c#l12 https://hg.python.org/cpython/file/27
by daveFNbuck 9y ago
You can see the CPython list implementation here: https://hg.python.org/cpython/file/273e17260d25/Objects/listobject.c#l12 https://hg.python.org/cpython/file/273e17260d25/Objects/list...
The CPython list implementation does indeed sacrifice performance to use less size. It uses a pre-allocated array for the list and when the list gets too large, it needs to allocate a new array to hold the list and re-insert all the items into the new array.
You may have done this in an intro CS class and doubled the array size to get an amortized O(1) append time, but you only need to increase the size by at least a constant fraction of the current size. Python increases by 1/8 of the current size, plus 6. This means more reallocations over a large number of operations, but less memory overhead at any given time.
Because of this implementation, you can pop from the right by just changing the size of the array, but to pop from the left requires shifting the entire array. You can pop the kth element from the right in O(k) time by just shifting those elements, which may be what the wiki means. I didn't read the code thoroughly enough to verify that it actually does this, but it seems reasonable.
Popping from the right is still slower than a deque because in order to save memory, the list gets resized whenever it falls below half of its maximum allocated size. A deque is always O(1) for every push/pop operation, but lists have occasional expensive operations that bump up the runtime a bit. Deques require linear time to access elements due to being implemented as doubly-linked lists. They're really only meant for accessing the elements on the ends.
You can get fast popleft on a list if you also keep a left pointer, but this complicates the implementation and has a corresponding performance penalty. You can even do a fast appendleft on a list if you allocate the elements so they start with empty cells on both the left and the right, but this makes the tradeoff between memory and performance even worse.