Thanks to visit codestin.com
Credit goes to www.pythonmorsels.com

The list insert method PREMIUM

Trey Hunner smiling in a t-shirt against a yellow wall
Trey Hunner
5 min. read 6 min. video Python 3.10—3.14
Python Morsels
Watch as video
05:40

Let's talk about how to add new items to the beginning of a list in Python, and why you might not want to.

Adding items to the beginning of a list

The list append method will add a new item to the end of a list:

>>> numbers = [2, 1, 4]
>>> numbers.append(7)
>>> numbers
[2, 1, 4, 7]

How could we add an item to the beginning of a list instead?

While the list append method adds items to the end of a list, the list insert method adds items before a given index.

The append method accepts just one argument – the argument to append.

>>> numbers.append(11)

The insert method accepts two arguments – the index to insert at, and the item to insert:

>>> numbers.insert(2, 3)

So we've just inserted the item 3 just before the index 2.

>>> numbers
[2, 1, 3, 4, 7, 11]

So to add a new item to the end of a list, we can call the list append method:

>>> colors = ["blue", "purple", "green"]
>>> colors.append("pink")

But to add a new item to the beginning of a list, we can call the insert method with an index of 0:

>>> colors.insert(0, "orange")
>>> colors
['orange', 'blue', 'purple', 'green', 'pink']

Why should you avoid using insert?

You should usually avoid using the list insert method because inserting an item to the beginning of a list can be much slower than appending an item to the end.

Let's append 200,000 numbers to the end of a new list:

>>> numbers = []
>>> for n in range(200_000):
...     numbers.append(n)
...

That was very fast, so fast that it felt instant.

Now let's insert 200,000 numbers to the beginning of a new list:

>>> numbers = []
>>> for n in range(200_000):
...     numbers.insert(0, n)
...

On my machine, this code takes multiple seconds to run.

In fact, if we did this same operation with a million items, that is five times more items, our code would take over five times more time.

On my machine, inserting 1 million items this way would take almost two minutes, while appending 1 million items to the end of a list would still be almost instant.

Why does insert take more time than append?

The problem isn't really that the insert method is slower than the append method.

The problem is that adding new items anywhere in a list, except at the end, requires shuffling other items around.

In computer science, there's a data structure called a stack. Stacks are a bit like a stack of plates.

Here we have created a new list:

>>> x = ["L", "I", "S", "T"]

Python's lists act kind of like stacks:

  ╰────T────╯
  ╰────S────╯
  ╰────I────╯
  ╰────L────╯
────────────────────────────────

When we append on exclamation mark to the end of our list:

>>> x = ["L", "I", "S", "T"]
>>> x.append("!")

An exclamation mark plate would be added to the top of our stack:

  ╰────!────╯
  ╰────T────╯
  ╰────S────╯
  ╰────I────╯
  ╰────L────╯
────────────────────────────────

The top of our stack represents the end of our list and the bottom of the stack represents the beginning of our list.

It's easy to add a new plate to the top of a stack. But it's challenging to add a new plate to the bottom of a stack.

Let's say we're inserting A to the beginning of the list:

>>> x = ["L", "I", "S", "T", "!"]
>>> x.insert(0, "A")

This requires us to add a new plate to the bottom of our stack.

Adding a new plate to the bottom requires removing each of the existing plates one after the other and temporarily storing them somewhere, and then putting that new item that you're adding into the original list.

                  ╰────L────╯
                  ╰────I────╯
                  ╰────S────╯
                  ╰────T────╯
  ╰────A────╯     ╰────!────╯
────────────────────────────────

We're not done yet, though. We now need to move all of those items that we moved out of the list back into the list, one-by-one.

  ╰────!────╯
  ╰────T────╯
  ╰────S────╯
  ╰────I────╯
  ╰────L────╯
  ╰────A────╯
────────────────────────────────

Python's list data type acts like a stack.

We can add a new item to the end of a list without much effort, but adding an item anywhere else in the list requires Python to remove all the items from that inserted item onward, then add the new item, and then add all those items back.

Removing items from a list

This same principle applies to removing items from a list also.

Here we're using the list pop method to repeatedly remove items from the end of a large list:

>>> numbers = list(range(200_000))
>>> total = 0
>>> while numbers:
...     total += numbers.pop()
...

This code runs very fast, so fast that we didn't even see it run.

Now let's pass an index of 0 while we pop. This will remove items repeatedly from the beginning of a large list:

>>> numbers = list(range(200_000))
>>> total = 0
>>> while numbers:
...     total += numbers.pop(0)
...

This code takes multiple seconds to run.

This is again due to the fact that lists are like stacks. Removing a plate from the top of a stack is easy. Removing a plate from the bottom of a stack requires shuffling around all of the plates above it.

Stacks vs. Queues

In computer science, stacks are optimized for adding and removing new items at the end.

You'll sometimes hear people refer to this as LIFO (Last In, First Out). This means that the last item that was appended would be the first item that was removed by default when you use the pop method on a list.

Queues are another data structure discussed in computer science. Queues are good for adding items to one end and removing them from the other end, just like a queue of customers in a checkout line.

These are referred to as FIFO (First In, First Out). That means the first item that was added to the queue would be the first item that's removed.

Double-ended queues are optimized for quickly adding and removing items from either end. A deque, pronounced "deck," acts like a double-ended queue:

>>> from collections import deque
>>> numbers = deque([2, 1, 3, 4, 7])

Just like a list, deques are efficient at appending items to the end. But deque objects also have an appendleft method, which can quickly insert items to the beginning:

>>> numbers.append(11)
>>> numbers.appendleft(9)
>>> numbers
deque([9, 2, 1, 3, 4, 7, 11])

There's also a pop method and a popleft method for efficiently removing items from the end or from the beginning.

Optimizing list operations

In Python, you can use the list insert method to insert an item before a specific index.

With a relatively small list, using insert is absolutely fine. But with a large list, inserting items at the beginning will have a noticeable time cost.

If you need to work with both ends of a list in Python, you may want to look into double-ended queues instead.

Python Morsels
Watch as video
05:40
This is a free preview of a premium screencast. You have 2 previews remaining.