Back to Blog
Python

Python reversed() Function: Syntax and Behavior

python reversed function: Learn how Python's reversed() function returns a lazy iterator, works with lists, strings, and ranges, and differs from reverse() and slicing.

reversed()built-in functionsiteratorssequence reversalmemory efficiency
A technical illustration showing a Python sequence being traversed in reverse by the reversed() function, with a lazy iterator concept.

The python reversed function — the built-in reversed() — returns a reverse iterator over a sequence. It accepts any object that supports the sequence protocol or implements __reversed__(). The critical detail is that it returns an iterator, not a list, which changes how you consume the result.

What reversed() Returns and Why It Matters

reversed() returns a reversed object, which is an iterator that produces elements from the end of the sequence to the beginning, one at a time. Because it is an iterator, you can traverse it only once. If you need to reuse the reversed elements, you must first convert the result to a list or tuple.

numbers = [1, 2, 3, 4, 5] rev = reversed(numbers) print(rev) # <list_reverseiterator object at 0x...>

The reversed object is lazy. It does not copy the sequence, and it does not compute all elements upfront. Each call to next() fetches the next element from the end, so the cost of reversal is spread across iteration rather than paid all at once.

Using reversed() with Common Sequence Types

reversed() works with any sequence that supports len() and integer indexing. That includes lists, tuples, strings, and ranges.

# List list(reversed([10, 20, 30])) # [30, 20, 10] # Tuple tuple(reversed((1, 2, 3))) # (3, 2, 1) # String ''.join(reversed("hello")) # 'olleh' # Range list(reversed(range(5))) # [4, 3, 2, 1, 0]

For strings, reversed() yields individual characters, so you need join() to reconstruct a string. For ranges, the result is a sequence of integers in reverse order. The same pattern applies to any type that implements the sequence protocol.

Converting the Iterator Back to a Container

Because reversed() returns an iterator, you often wrap it in list(), tuple(), or join() depending on the target type. This conversion materializes the full sequence in memory, which matters when working with large data.

data = [1, 2, 3, 4, 5] reversed_list = list(reversed(data)) reversed_tuple = tuple(reversed(data))

If you only need to iterate once — for example, in a for loop — you can use the iterator directly without conversion.

for item in reversed(data): print(item)

This avoids creating a second copy of the data. The iterator holds a reference to the original sequence and an internal index, so the memory overhead stays constant regardless of sequence length.

reversed() vs list.reverse() vs Slicing

Three common ways to reverse a sequence, with different behavior:

ApproachReturnsMutates original?Memory
reversed(seq)iteratorNoO(1)
seq.reverse()NoneYesO(1)
seq[::-1]new listNoO(n)

list.reverse() reverses the list in place and returns None. It only works on lists. seq[::-1] creates a full copy of the sequence in reverse order, which is simple but uses O(n) memory. reversed() is the only option that gives a lazy, non-copying view of the sequence.

Choose reversed() when you need to iterate in reverse without modifying the original or allocating a copy. Choose [::-1] when you need a new reversed list that you will keep. Choose .reverse() when you own the list and want to mutate it in place.

Custom Objects and the Sequence Protocol

reversed() works with any object that implements __len__ and __getitem__ with integer indices, or that defines __reversed__(). If an object defines __reversed__(), Python calls it directly and returns whatever iterator that method provides.

class ReverseRange: def __init__(self, start, stop): self.start = start self.stop = stop def __len__(self): return max(0, self.stop - self.start) def __getitem__(self, index): if index < 0 or index >= len(self): raise IndexError return self.start + index list(reversed(ReverseRange(1, 5))) # [4, 3, 2, 1]

ReverseRange behaves like a half-open range. reversed() uses len() to find the last index and then walks backward with __getitem__. If the object defines __reversed__(), that method takes precedence and can return any iterator, which is useful when the natural reverse order differs from the sequence order.

Memory and Runtime Behavior

Because reversed() is lazy, it adds O(1) memory overhead regardless of the sequence size. The iterator holds a reference to the sequence and an index, then decrements the index on each step. This is the main advantage over slicing, which copies every element.

The runtime cost is one __getitem__ call per element, the same cost as forward iteration. There is no hidden sorting or copying. If you repeatedly need the reversed form, materializing it once with list(reversed(seq)) may be cheaper than creating a fresh iterator each time, but for single-pass loops the lazy version is preferable.

Common Mistakes and Edge Cases

A frequent mistake is assuming reversed() works on any iterable. It does not work on generators, iterators, or sets, because those do not support len() and integer indexing.

# These raise TypeError reversed(iter([1, 2, 3])) reversed({1, 2, 3})

Another mistake is expecting reversed() to return a list and then indexing into the result. The reversed object does not support indexing; you must convert it first.

Also note that reversed() does not modify the original sequence. If you need the original mutated, use .reverse() instead.

python reversed function: Practical Usage and Code Examples | RYUSLOG DEV