Lists highlight some of Python’s greatest strengths. Lists are similar to the arrays found in other languages but more flexible and open to manipulation. Python even has built-in list method options, such as append, which make operations that would be troublesome in an array as simple as passing a variable. However, while list has an append method it doesn’t have a prepend counterpart. Python makes it easy to add items to the end of a list, but not to the beginning. This raises the question of how to prepend to list in Python.
Prepend and Append in Python
The fact that Python lists have an append but no prepend method might seem strange. But the heart of the matter comes down to performance. As you’ll soon see, Python lists are constructed in a manner that allows for quick and efficient appending of data. But that efficiency only extends as far as adding data to the end of a python list. Adding data to the beginning of a list is another matter. It’s possible and even easy to do so, but not very efficient.
A Deeper Look Into List Prepending
One of the nice things about lists is that they alleviate a lot of the work which goes into managing arrays in other programming languages. But, in fact, you are technically using arrays when you use a Python list. Python is essentially abstracting away most of the work associated with using an array. In a sense, a Python list is an array where the interpreter is doing all of the heavy lifting behind the scenes. Every Python list is actually an array of pointers that are all internally managed by the Python interpreter. The underlying nature of lists will almost never come up when you’re writing Python code. However, there are rare exceptions to that rule. And reorganizing data on the fly is one of those exceptions.
Adding data to the beginning of a list essentially causes the Python interpreter to recalculate every pointer within the underlying array. Recreating the original list with a new element at the beginning will obviously add some computational overhead. However, the exact procedure used to accomplish that feat can make a world of difference. For example, consider the following code.
ourList = [‘is’,’the’,’list.’]
print(ourList)
ourList = [“This”] + ourList
print(ourList)
We begin by creating a list and printing the contents to screen. We’re obviously missing a word at the beginning though. So in the next line we recreate the list, assign it back to ourList, but this time we place the missing “This” at the beginning. Finally, we print out the list to show that we’ve managed to essentially insert a new element into our list. This does accomplish our initial objective of prepending an item to the beginning of a list. However, it’s exactly the type of computationally inefficient procedure that Python’s syntax is trying to prevent. So how could we go about prepending an item in a more efficient way?
Deque and More Effective Forms of List Manipulation
The simplest answer is to avoid prepending to a list in the first place. It’s generally accepted that you’re better off using a data type from collections called deque if you’ll be regularly adding data to both the beginning and end of a data structure. The name deque, Doubly Ended Queue, even refers to the fact that you can efficiently add to both sides of the structure.
A deque operates in a similar way to traditional Python lists. However, it receives a speed boost to prepends due to the fact that it’s internally treated as a linked list. The following code builds on the prior example to highlight deque’s ability to easily prepend a single element to the collection.
from collections import deque
ourDeque = deque([‘is’,’the’,’deque ‘])
print (ourDeque)
ourDeque.appendleft(“This”)
print (ourDeque)
However, there are instances where you might specifically need to use a list. When that’s the case, there are methods to prepend data that are more efficient than manually recreating the list. List slicing at a [0:0] position is an extremely easy way to essentially prepend data into a list. The following code demonstrates how a list slice can essentially work as a prepend.
ourList = [‘is’,’the’,’list.’]
print(ourList)
ourList[0:0] = [“This”]
print(ourList)
We modify the original example to slice at [0:0] and then print the result. And we see that “This” has been prepended into the list without needing to manually recreate it. We can also do something similar with the Python list’s insert method. The following example highlights the fact that we can use a native list method to prepend items.
ourList = [‘is’,’the’,’list.’]
print(ourList)
ourList.insert(0,”This”)
print(ourList)
The syntax here isn’t that different than when we use slice. We still explicitly state that we want to insert “This” into the beginning of the list. The main difference is that insert is a built-in method of lists. Many people feel that this makes it a slightly cleaner way to go about prepending data. As such, it’s generally considered the preferred method of prepending data to a list. Though the overall efficiency of using insert and slice to prepend data into lists is roughly equivalent. Both methods are typically about twice as fast as manually recreating a list, as we did with the very first example. The Python interpreter can step in to handle things a little more efficiently when we essentially tell it what our end goal is by using slice or insert.