# Reverse Python Lists: Beyond .reverse() and reversed()

Are you diving deeper into Python lists and wanting to learn about different ways to reverse them? If so, then this tutorial is for you. Here, you’ll learn about a few Python tools and techniques that are handy when it comes to reversing lists or manipulating them in reverse order. This knowledge will complement and improve your list-related skills and make you more proficient with them.

In this tutorial, you’ll learn how to:

• Reverse existing lists in place using `.reverse()` and other techniques
• Create reversed copies of existing lists using `reversed()` and slicing
• Use iteration, comprehensions, and recursion to create reversed lists
• Iterate over your lists in reverse order
• Sort your lists in reverse order using `.sort()` and `sorted()`

To get the most out of this tutorial, it would be helpful to know the basics of iterables, `for` loops, lists, list comprehensions, generator expressions, and recursion.

## Reversing Python Lists

Sometimes you need to process Python lists starting from the last element down to the first—in other words, in reverse order. In general, there are two main challenges related to working with lists in reverse:

1. Reversing a list in place
2. Creating reversed copies of an existing list

To meet the first challenge, you can use either `.reverse()` or a loop that swaps items by index. For the second, you can use `reversed()` or a slicing operation. In the next sections, you’ll learn about different ways to accomplish both in your code.

### Reversing Lists in Place

Like other mutable sequence types, Python lists implement `.reverse()`. This method reverses the underlying list in place for memory efficiency when you’re reversing large list objects. Here’s how you can use `.reverse()`:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> digits.reverse()
>>> digits
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
``````

When you call `.reverse()` on an existing list, the method reverses it in place. This way, when you access the list again, you get it in reverse order. Note that `.reverse()` doesn’t return a new list but `None`:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> reversed_digits = digits.reverse()
>>> reversed_digits is None
True
``````

Trying to assign the return value of `.reverse()` to a variable is a common mistake related to using this method. The intent of returning `None` is to remind its users that `.reverse()` operates by side effect, changing the underlying list.

Okay! That was quick and straightforward! Now, how can you reverse a list in place by hand? A common technique is to loop through the first half of it while swapping each element with its mirror counterpart on the second half of the list.

Python provides zero-based positive indices to walk sequences from left to right. It also allows you to navigate sequences from right to left using negative indices:

This diagram shows that you can access the first element of the list (or sequence) using either `0` or `-5` with the indexing operator, like in `sequence[0]` and `sequence[-5]`, respectively. You can use this Python feature to reverse the underlying sequence in place.

For example, to reverse the list represented in the diagram, you can loop over the first half of the list and swap the element at index `0` with its mirror at index `-1` in the first iteration. Then you can switch the element at index `1` with its mirror at index `-2` and so on until you get the list reversed.

Here’s a representation of the whole process:

To translate this process into code, you can use a `for` loop with a `range` object over the first half of the list, which you can get with `len(digits) // 2`. Then you can use a parallel assignment statement to swap the elements, like this:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> for i in range(len(digits) // 2):
...     digits[i], digits[-1 - i] = digits[-1 - i], digits[i]
...

>>> digits
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
``````

This loop iterates through a `range` object that goes from `0` to `len(digits) // 2`. Each iteration swaps an item from the first half of the list with its mirror counterpart in the second half. The expression `-1 - i` inside the indexing operator, `[]`, guarantees access to the mirror item. You can also use the expression `-1 * (i + 1)` to provide the corresponding mirror index.

Besides the above algorithm, which takes advantage of index substitution, there are a few different ways to reverse lists by hand. For example, you can use `.pop()` and `.insert()` like this:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> for i in range(len(digits)):
...     last_item = digits.pop()
...     digits.insert(i, last_item)
...

>>> digits
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
``````

In the loop, you call `.pop()` on the original list without arguments. This call removes and returns the last item in the list, so you can store it in `last_item`. Then `.insert()` moves `last_item` to the position at index `i`.

For example, the first iteration removes `9` from the right end of the list and stores it in `last_item`. Then it inserts `9` at index `0`. The next iteration takes `8` and moves it to index `1`, and so on. At the end of the loop, you get the list reversed in place.

### Creating Reversed Lists

If you want to create a reversed copy of an existing list in Python, then you can use `reversed()`. With a list as an argument, `reversed()` returns an iterator that yields items in reverse order:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> reversed_digits = reversed(digits)
>>> reversed_digits
<list_reverseiterator object at 0x7fca9999e790>

>>> list(reversed_digits)
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
``````

In this example, you call `reversed()` with `digits` as an argument. Then you store the resulting iterator in `reversed_digits`. The call to `list()` consumes the iterator and returns a new list containing the same items as `digits` but in reverse order.

An important point to note when you’re using `reversed()` is that it doesn’t create a copy of the input list, so changes on it affect the resulting iterator:

>>>
``````>>> fruits = ["apple", "banana", "orange"]

>>> reversed_fruit = reversed(fruits)  # Get the iterator
>>> fruits[-1] = "kiwi"  # Modify the last item
>>> next(reversed_fruit)  # The iterator sees the change
'kiwi'
``````

In this example, you call `reversed()` to get the corresponding iterator over the items in `fruits`. Then you modify the last fruit. This change affects the iterator. You can confirm that by calling `next()` to get the first item in `reversed_fruit`.

If you need to get a copy of `fruits` using `reversed()`, then you can call `list()`:

>>>
``````>>> fruits = ["apple", "banana", "orange"]

>>> list(reversed(fruits))
['orange', 'banana', 'apple']
``````

As you already know, the call to `list()` consumes the iterator that results from calling `reversed()`. This way, you create a new list as a reversed copy of the original one.

Python 2.4 added `reversed()`, a universal tool to facilitate reverse iteration over sequences, as stated in PEP 322. In general, `reversed()` can take any objects that implement a `.__reversed__()` method or that support the sequence protocol, consisting of the `.__len__()` and `.__getitem__()` special methods. So, `reversed()` isn’t limited to lists:

>>>
``````>>> list(reversed(range(10)))
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

>>> list(reversed("Python"))
['n', 'o', 'h', 't', 'y', 'P']
``````

Here, instead of a list, you pass a `range` object and a string as arguments to `reversed()`. The function does its job as expected, and you get a reversed version of the input data.

Another important point to highlight is that you can’t use `reversed()` with arbitrary iterators:

>>>
``````>>> digits = iter([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

>>> reversed(digits)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'list_iterator' object is not reversible
``````

In this example, `iter()` builds an iterator over your list of numbers. When you call `reversed()` on `digits`, you get a `TypeError`.

Iterators implement the `.__next__()` special method to walk through the underlying data. They’re also expected to implement the `.__iter__()` special method to return the current iterator instance. However, they’re not expected to implement either `.__reversed__()` or the sequence protocol. So, `reversed()` doesn’t work for them. If you ever need to reverse an iterator like this, then you should first convert it to a list using `list()`.

Another point to note is that you can’t use `reversed()` with unordered iterables:

>>>
``````>>> digits = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

>>> reversed(digits)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'set' object is not reversible
``````

In this example, when you try to use `reversed()` with a `set` object, you get a `TypeError`. This is because sets don’t keep their items ordered, so Python doesn’t know how to reverse them.

### Reversing Lists Through Slicing

Since Python 1.4, the slicing syntax has had a third argument, called `step`. However, that syntax initially didn’t work on built-in types, such as lists, tuples, and strings. Python 2.3 extended the syntax to built-in types, so you can use `step` with them now. Here’s the full-blown slicing syntax:

``````a_list[start:stop:step]
``````

This syntax allows you to extract all the items in `a_list` from `start` to `stop − 1` by `step`. The third offset, `step`, defaults to `1`, which is why a normal slicing operation extracts the items from left to right:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> digits[1:5]
[1, 2, 3, 4]
``````

With `[1:5]`, you get the items from index `1` to index `5 - 1`. The item with the index equal to `stop` is never included in the final result. This slicing returns all the items in the target range because `step` defaults to `1`.

If you use a different `step`, then the slicing jumps as many items as the value of `step`:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> digits[0::2]
[0, 2, 4, 6, 8]

>>> digits[::3]
[0, 3, 6, 9]
``````

In the first example, `[0::2]` extracts all items from index `0` to the end of `digits`, jumping over two items each time. In the second example, the slicing jumps `3` items as it goes. If you don’t provide values to `start` and `stop`, then they are set to `0` and to the length of the target sequence, respectively.

If you set `step` to `-1`, then you get a slice with the items in reverse order:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> # Set step to -1
>>> digits[len(digits) - 1::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

>>> digits
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
``````

This slicing returns all the items from the right end of the list (`len(digits) - 1`) back to the left end because you omit the second offset. The rest of the magic in this example comes from using a value of `-1` for `step`. When you run this trick, you get a copy of the original list in reverse order without affecting the input data.

If you fully rely on implicit offsets, then the slicing syntax gets shorter, cleaner, and less error-prone:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> # Rely on default offset values
>>> digits[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
``````

Here, you ask Python to give you the complete list (`[::-1]`) but going over all the items from back to front by setting `step` to `-1`. This is pretty neat, but `reversed()` is more efficient in terms of execution time and memory usage. It’s also more readable and explicit. So these are points to consider in your code.

Another technique to create a reversed copy of an existing list is to use `slice()`. The signature of this built-in function is like this:

``````slice(start, stop, step)
``````

This function works similarly to the indexing operator. It takes three arguments with similar meaning to those used in the slicing operator and returns a slice object representing the set of indices returned by `range(start, stop, step)`. That sounds complicated, so here are some examples of how `slice()` works:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> slice(0, len(digits))
slice(0, 10, None)

>>> digits[slice(0, len(digits))]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> slice(len(digits) - 1, None, -1)
slice(9, None, -1)

>>> digits[slice(len(digits) - 1, None, -1)]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
``````

The first call to `slice()` is equivalent to `[0:len(digits)]`. The second call works the same as `[len(digits) - 1::-1]`. You can also emulate the slicing `[::-1]` using `slice(None, None, -1)`. In this case, passing `None` to `start` and `stop` means that you want a slice from the beginning to the end of the target sequence.

Here’s how you can use `slice()` to create a reversed copy of an existing list:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> digits[slice(None, None, -1)]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
``````

The `slice` object extracts all the items from `digits`, starting from the right end back to the left end, and returns a reversed copy of the target list.

## Generating Reversed Lists by Hand

So far, you’ve seen a few tools and techniques to either reverse lists in place or create reversed copies of existing lists. Most of the time, these tools and techniques are the way to go when it comes to reversing lists in Python. However, if you ever need to reverse lists by hand, then it’d be beneficial for you to understand the logic behind the process.

In this section, you’ll learn how to reverse Python lists using loops, recursion, and comprehensions. The idea is to get a list and create a copy of it in reverse order.

### Using a Loop

The first technique you’ll use to reverse a list involves a `for` loop and a list concatenation using the plus symbol (`+`):

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> def reversed_list(a_list):
...     result = []
...     for item in a_list:
...         result = [item] + result
...     return result
...

>>> reversed_list(digits)
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
``````

Every iteration of the `for` loop takes a subsequent item from `a_list` and creates a new list that results from concatenating `[item]` and `result`, which initially holds an empty list. The newly created list is reassigned to `result`. This function doesn’t modify `a_list`.

You can also take advantage of `.insert()` to create reversed lists with the help of a loop:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> def reversed_list(a_list):
...     result = []
...     for item in a_list:
...         result.insert(0, item)
...     return result
...

>>> reversed_list(digits)
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
``````

The call to `.insert()` inside the loop inserts subsequent items at the `0` index of `result`. At the end of the loop, you get a new list with the items of `a_list` in reverse order.

Using `.insert()` like in the above example has a significant drawback. Insert operations at the left end of Python lists are known to be inefficient regarding execution time. That’s because Python needs to move all the items one step back to insert the new item at the first position.

### Using Recursion

You can also use recursion to reverse your lists. Recursion is when you define a function that calls itself. This creates a loop that can become infinite if you don’t provide a base case that produces a result without calling the function again.

You need the base case to end the recursive loop. When it comes to reversing lists, the base case would be reached when the recursive calls get to the end of the input list. You also need to define the recursive case, which reduces all successive cases toward the base case and, therefore, to the loop’s end.

Here’s how you can define a recursive function to return a reversed copy of a given list:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> def reversed_list(a_list):
...     if len(a_list) == 0:  # Base case
...         return a_list
...     else:
...         # print(a_list)
...         # Recursive case
...         return reversed_list(a_list[1:]) + a_list[:1]
...

>>> reversed_list(digits)
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
``````

Inside `reversed_list()`, you first check the base case, in which the input list is empty and makes the function return. The `else` clause provides the recursive case, which is a call to `reversed_list()` itself but with a slice of the original list, `a_list[1:]`. This slice contains all the items in `a_list` except for the first item, which is then added as a single-item list (`a_list[:1]`) to the result of the recursive call.

The commented call to `print()` at the beginning of the `else` clause is just a trick intended to show how subsequent calls reduce the input list toward the base case. Go ahead and uncomment the line to see what happens!

### Using a List Comprehension

If you’re working with lists in Python, then you probably want to consider using a list comprehension. This tool is quite popular in the Python space because it represents the Pythonic way to process lists.

Here’s an example of how to use a list comprehension to create a reversed list:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> last_index = len(digits) - 1

>>> [digits[i] for i in range(last_index, -1, -1)]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
``````

The magic in this list comprehension comes from the call to `range()`. In this case, `range()` returns indices from `len(digits) - 1` back to `0`. This makes the comprehension loop iterate over the items in `digits` in reverse, creating a new reversed list in the process.

## Iterating Through Lists in Reverse

Up to this point, you’ve learned how to create reversed lists and also how to reverse existing lists in place, either by using tools specially designed to accomplish that task or by using your own hand-coded solutions.

In day-to-day programming, you might find that iterating through existing lists and sequences in reverse order, typically known as reverse iteration, is a fairly common requirement. If that’s your case, then you have several options. Depending on your specific needs, you can use:

• The built-in function `reversed()`
• The slicing operator, `[::]`
• The special method `.__reversed__()`

In the following few sections, you’ll learn about all these options and how they can help you iterate over lists in reverse order.

### The Built-in `reversed()` Function

Your first approach to iterating over a list in reverse order might be to use `reversed()`. This built-in function was specially designed to support reverse iteration. With a list as an argument, it returns an iterator that yields the input list items in reverse order.

Here’s how you can use `reversed()` to iterate through the items in a list in reverse order:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> for digit in reversed(digits):
...     print(digit)
...
9
8
7
6
5
4
3
2
1
0
``````

The first thing to note in this example is that the `for` loop is highly readable. The name of `reversed()` clearly expresses its intent, with the subtle detail of communicating that the function doesn’t produce any side effects. In other words, it doesn’t modify the input list.

The loop is also efficient in terms of memory usage because `reversed()` returns an iterator that yields items on demand without storing them all in memory at the same time. Again, a subtle detail to note is that if the input list changes during the iteration, then the iterator sees the changes.

### The Slicing Operator, `[::-1]`

The second approach to reverse iteration is to use the extended slicing syntax you saw before. This syntax does nothing in favor of memory efficiency, beauty, or clarity. Still, it provides a quick way to iterate over a reversed copy of an existing list without the risk of being affected by changes in the original list.

Here’s how you can use `[::-1]` to iterate through a copy of an existing list in reverse order:

>>>
``````>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> for digit in digits[::-1]:
...     print(digit)
...
9
8
7
6
5
4
3
2
1
0
``````

When you slice a list like in this example, you create a reversed copy of the original list. Initially, both lists contain references to the same group of items. However, if you assign a new value to a given item in the original list, like in `digits[0] = "zero"`, then the reference changes to point to the new value. This way, changes on the input list don’t affect the copy.

You can take advantage of this kind of slicing to safely modify the original list while you iterate over its old items in reverse order. For example, say you need to iterate over a list of numbers in reverse order and replace every number with its square value. In this case, you can do something like this:

>>>
``````>>> numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> for i, number in enumerate(numbers[::-1]):
...     numbers[i] = number ** 2
...

>>> # Square values in reverse order
>>> numbers
[81, 64, 49, 36, 25, 16, 9, 4, 1, 0]
``````

Here, the loop iterates through a reversed copy of `numbers`. The call to `enumerate()` provides ascending zero-based indices for each item in the reversed copy. That allows you to modify `numbers` during the iteration. Then the loop modifies the `numbers` by replacing each item with its square value. As a result, `numbers` ends up containing square values in reverse order.

### The Special Method `.__reversed__()`

Python lists implement a special method called `.__reversed__()` that enables reverse iteration. This method provides the logic behind `reversed()`. In other words, a call to `reversed()` with a list as an argument triggers an implicit call to `.__reversed__()` on the input list.

This special method returns an iterator over the items of the current list in reverse order. However, `.__reversed__()` isn’t intended to be used directly. Most of the time, you’ll use it to equip your own classes with reverse iteration capabilities.

For example, say you want to iterate over a range of floating-point numbers. You can’t use `range()`, so you decide to create your own class to approach this specific use case. You end up with a class like this:

``````# float_range.py

class FloatRange:
def __init__(self, start, stop, step=1.0):
if start >= stop:
raise ValueError("Invalid range")
self.start = start
self.stop = stop
self.step = step

def __iter__(self):
n = self.start
while n < self.stop:
yield n
n += self.step

def __reversed__(self):
n = self.stop - self.step
while n >= self.start:
yield n
n -= self.step
``````

This class isn’t perfect. It’s just your first version. However, it allows you to iterate through an interval of floating-point numbers using a fixed increment value, `step`. In your class, `.__iter__()` provides support for normal iteration and `.__reversed__()` supports reverse iteration.

To use `FloatRange`, you can do something like this:

>>>
``````>>> from float_range import FloatRange

>>> for number in FloatRange(0.0, 5.0, 0.5):
...     print(number)
...
0.0
0.5
1.0
1.5
2.0
2.5
3.0
3.5
4.0
4.5
``````

The class supports normal iteration, which, as mentioned, is provided by `.__iter__()`. Now you can try to iterate in reverse order using `reversed()`:

>>>
``````>>> from float_range import FloatRange

>>> for number in reversed(FloatRange(0.0, 5.0, 0.5)):
...     print(number)
...
4.5
4.0
3.5
3.0
2.5
2.0
1.5
1.0
0.5
0.0
``````

In this example, `reversed()` relies on your `.__reversed__()` implementation to provide the reverse iteration functionality. This way, you have a working floating-point iterator.

## Reversing Python Lists: A Summary

Up to this point, you’ve learned a lot about reversing lists using different tools and techniques. Here’s a table that summarizes the more important points you’ve already covered:

Feature `.reverse()` `reversed()` `[::-1]` Loop List Comp Recursion
Modifies the list in place ✔/❌
Creates a copy of the list ✔/❌
Is fast
Is universal

A quick look at this summary will allow you to decide which tool or technique to use when you’re reversing lists in place, creating reversed copies of existing lists, or iterating over your lists in reverse order.

## Sorting Python Lists in Reverse Order

Another interesting option when it comes to reversing lists in Python is to use `.sort()` and `sorted()` to sort them in reverse order. To do that, you can pass `True` to their respective `reverse` argument.

The goal of `.sort()` is to sort the items of a list. The sorting is done in place, so it doesn’t create a new list. If you set the `reverse` keyword argument to `True`, then you get the list sorted in descending or reverse order:

>>>
``````>>> digits = [0, 5, 7, 3, 4, 9, 1, 6, 3, 8]

>>> digits.sort(reverse=True)
>>> digits
[9, 8, 7, 6, 5, 4, 3, 3, 1, 0]
``````

Now your list is fully sorted and also in reverse order. This is quite convenient when you’re working with some data and you need to sort it and reverse it at the same time.

On the other hand, if you want to iterate over a sorted list in reverse order, then you can use `sorted()`. This built-in function returns a new list containing all the items of the input iterable in order. If you pass `True` to its `reverse` keyword argument, then you get a reversed copy of the initial list:

>>>
``````>>> digits = [0, 5, 7, 3, 4, 9, 1, 6, 3, 8]

>>> sorted(digits, reverse=True)
[9, 8, 7, 6, 5, 4, 3, 3, 1, 0]

>>> for digit in sorted(digits, reverse=True):
...     print(digit)
...
9
8
7
6
5
4
3
3
1
0
``````

The `reverse` argument to `sorted()` allows you to sort iterables in descending order instead of in ascending order. So, if you need to create sorted lists in reverse order, then `sorted()` is for you.

## Conclusion

Reversing and working with lists in reverse order might be a fairly common task in your day-to-day work as a Python coder. In this tutorial, you took advantage of a couple of Python tools and techniques to reverse your lists and manage them in reverse order.

In this tutorial, you learned how to:

• Reverse your lists in place using `.reverse()` and other techniques
• Use `reversed()` and slicing to create reversed copies of your lists
• Use iteration, comprehensions, and recursion to create reversed lists
• Iterate through your lists in reverse order
• Sort lists in reverse order using `.sort()` and `sorted()`

All of this knowledge helps you improve your list-related skills. It provides you with the required tools to be more proficient when you’re working with Python lists.

🐍 Python Tricks 💌

Get a short & sweet Python Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.

Leodanis is an industrial engineer who loves Python and software development. He's a self-taught Python developer with 6+ years of experience. He's an avid technical writer with a growing number of articles published on Real Python and other sites.

Each tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are: