Python Reverse List

Reversing a list is a relatively common operation in Python. This is a common interview question and a common test question. It comes up in the real world sometimes as well.

We can use this as an example list:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Our goal is to reverse this list for something like this:
[9, 8, 7, 6, 5, 4, 3, 2, 1]

Thereare a number of different ways to reverse a list in Python. We are going to cover a few of these different methods here. Note the difference between reverse() and reversed(). Both of these can be used and are demonstrated below.

Using The Built-in Function: reverse()

One method is to use the reverse() function. This function is part of every list object. It provides you with in-place reversal meaning that it modifies the original list. It just moves everything around in place. This will use less memory because it doesn't create a second copy of the list. The function doesn't return a new list. It just returns 'None'.

>>> list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list1.reverse()
>>> list1
[9, 8, 7, 6, 5, 4, 3, 2, 1]

If you check the list after having called reverse() you will notice that it has been changed. This is probably the most straight forward and "Pythonic" way of doing things.

List Slicing

Another excellent way of reversing a list in Python is to use list slicing. This is a really neat way of doing things.

This is my favorite method and it is super easy: >>> list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list1[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1]

Some people say that this method isn't the most "Pythonic" way of doing things. Personally, this is my favorite but that is probably because I'm coming from a PERL background.

Using this method, new copy of the list is created. This is a shallow copy meaning that even though it creates a new list the values reference the old values. A new object is created but the data points to original data. It is kind of like having a new view of the same data. The original is still left in the same order. We'll cover this idea in a little more detail below.

This method uses more memory since it creates a new object.

A Bit on Slicing Syntax

Slicing syntax works like this: [start:stop:step]

The square bracket takes up to 3 options separated by colons. These are the start index, the end index, and the amount to increment by. Basically we are telling it to take a slice of the list starting from the first element and going to the last except that the -1 tells it to count backwards.

Sidetrack: Lists and Shallow Copies

We're probably getting a little off track but here is another example. This shows us saving a reversed slice to a new list. We can then modify the contents of this new list without the first list being touched. This works fine so long as the items in the list are only simple values.

>>> list1
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> test = list1[::-1]
>>> test
[9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> list1
[1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> test[5]=77
>>> test
[9, 8, 7, 6, 5, 77, 3, 2, 1]
>>> list1
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Lets take this a step further and see what happens when we have a nested list. Assigning values to elements in the nested list from the new reversed list will modify it in the original as well. Basically, objects in the list are just pointers referencing the object. So both the new and the old list are referencing the same nested list. Here is another example th at shows exactly that.

>>> a = [1, 2, 3, 4, 5, [1, 2, 3]]
>>> b = a[::-1]
>>> a
[1, 2, 3, 4, 5, [1, 2, 3]]
>>> b
[[1, 2, 3], 5, 4, 3, 2, 1]
>>> b[1]=77
>>> a
[1, 2, 3, 4, 5, [1, 2, 3]]
>>> b
[[1, 2, 3], 77, 4, 3, 2, 1]
>>> b[0][0]=88
>>> a
[1, 2, 3, 4, 5, [88, 2, 3]]
>>> b
[[88, 2, 3], 77, 4, 3, 2, 1]
>>> b[0]=99
>>> a
[1, 2, 3, 4, 5, [88, 2, 3]]
>>> b
[99, 77, 4, 3, 2, 1]

Using An Iterator

The reversed() function creates an iterator.

NOTE - This is not to be confused with the reverse() function.

You can use thereversed() function to create an iterator and then loop over it. This doesn't really give you a new list though. It just prints the elements in reverse order.

>>> list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> for i in reversed(list1):
...     print(i)
...
9
8
7
6
5
4
3
2
1

The printed output from the reversed function just returns the memory address of an iterator. So that isn't what we want by itself either.

>>> reversed(list1)

We can pass this iterator to a list constructor creating a new list. This works great.

>>> list2 = list(reversed(list1))
>>> list1
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list2
[9, 8, 7, 6, 5, 4, 3, 2, 1]

Another alternative way to do this would be to use a list comprehension. These are alwasy fun.

>>> print [x for x in reversed(list1)]
[9, 8, 7, 6, 5, 4, 3, 2, 1]

Doing It The Hardway - From Scratch

If you don't want to use any built-in functions or features, you can build your own function to reverse a list from scratch. This is a common use case for exam questions and interview questions. It is also great if you just happen to want to play around with algorithms. If you really just want to get stuff done, this isn't the way to go.

Here is our first example from scratch. It creates a new empty list the same size as the original. It then loops through the original list saving values to the new list starting at the end of the new list. Finally, it returns the new list.

>>> def test1(list1):
    l = len(list1)
    list2 = [None]*l
    j = l
    for i in list1:
        j = j - 1
        list2[j] = i
    return list2
>>>
>>> list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> test1(list1)
[9, 8, 7, 6, 5, 4, 3, 2, 1]
>>>

Here is our second example from scratch. Modifies the original list in place. It basically moves through the list from each end swapping elements. By the time it hits the center of the list it will have only had to cycle through half of the number of elements in the list.

>>> def test2(list1):
    s = 0
    e = len(list1)-1
    while s<e:
        list1[s],list1[e] = list1[e],list1[s]
        s += 1
        e -= 1
    return list1
>>>
>>> list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> test2(list1)
[9, 8, 7, 6, 5, 4, 3, 2, 1]
>>>