What’s the best way to reverse a string in Python? Granted, string reversal isn’t used all that often in day-to-day programming, but it’s a popular interviewing question:
# You have this: 'TURBO' # And you want that: 'OBRUT'
One variation of this question is to write a function that checks whether a given string is a palindrome, that is, whether or not it reads the same forwards and backwards:
def is_palindrome(string): reversed_string = # ??? return string == reversed_string >>> is_palindrome('TACOCAT') True >>> is_palindrome('TURBO') False
Clearly, we’ll need to figure out how to reverse a string to implement this
is_palindrome function in Python…so how do you do it?
str string objects have no built-in
.reverse() method like you might expect if you’re coming to Python from a different language, like Java or C#—the following approach will fail:
>>> 'TURBO'.reverse() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'str' object has no attribute 'reverse'
In this tutorial you’ll learn the three major ways to reverse strings in Python:
Option 1: Reversing a Python String With the “
[::-1]” Slicing Trick
Strings follow the sequence protocol in Python. And all sequences support an interesting feature called slicing. You can view slicing as an extension of the square-brackets indexing syntax.
It includes a special case where slicing a sequence with “
[::-1]” produces a reversed copy. Because Python strings are sequences this is a quick and easy way to get a reversed copy of a string:
>>> 'TURBO'[::-1] 'OBRUT'
Of course, you can wrap this (slightly unwieldy) slicing expression into a named function to make it more obvious what the code does:
def reverse_string1(s): """Return a reversed copy of `s`""" return s[::-1] >>> reverse_string1('TURBO') 'OBRUT'
So, how do you like this solution?
It’s short and sweet—but, in my mind, the biggest downside to reversing a string with the slicing syntax is that it uses an advanced Python feature that some developers would say is “arcane.”
I don’t blame them—list slicing can be difficult to understand the first time you encounter its quirky and terse syntax.
When I’m reading Python code that makes use of slicing I often have to slow down and concentrate to “mentally parse” the statement, to make sure I understand what’s going on.
My biggest gripe here is that the “
[::-1]” slicing syntax doesn’t communicate clearly enough that it creates a reversed copy of the original string.
For this reason I feel like using Python’s slicing feature to reverse a string is a decent solution, but it can be a difficult to read to the uninitiated.
[ You can learn more about slicing in this article. ]
Option 2: Reversing a Python String Using
>>> for elem in reversed('TURBO'): ... print(elem) O B R U T
reversed() does not modify the original string (which wouldn’t work anyway as strings are immutable in Python.) What happens is that you get a “view” into the existing string you can use to look at all the elements in reverse order.
This is a powerful technique that takes advantage of Python’s iterator protocol.
So far, all you saw was how to iterate over the characters of a string in reversed order. But how can you use this technique to create a reversed copy of a Python string with the
>>> ''.join(reversed('TURBO')) 'OBRUT'
This code snippet used the
.join() method to merge all of the characters resulting from the reversed iteration into a new string. Pretty neat, eh?
Of course, you can once again extract this code into a separate function to create a proper “reverse string” function in Python. Here’s how:
def reverse_string2(s): """Return a reversed copy of `s`""" return "".join(reversed(s)) >>> reverse_string2('TURBO') 'OBRUT'
I really like this reverse iterator approach for reversing strings in Python.
It communicates clearly what is going on, and even someone new to the language would intuitively understand that I’m creating a reversed copy of the original string.
And while understanding how iterators work at a deeper level is helpful, it’s not absolutely necessary to use this technique.
One more approach you should check out:
Option 3: The “Classic” In-Place String Reversal Algorithm Ported to Python
This is the “classic” textbook in-place string reversal algorithm, ported to Python. Because Python strings are immutable, you first need to convert the input string into a mutable list of characters, so you can perform the in-place character swap:
def reverse_string3(s): """Return a reversed copy of `s`""" chars = list(s) for i in range(len(s) // 2): tmp = chars[i] chars[i] = chars[len(s) - i - 1] chars[len(s) - i - 1] = tmp return ''.join(chars) >>> reverse_string3('TURBO') 'OBRUT'
As you can tell, this solution is quite unpythonic and not very idiomatic at all. It doesn’t play to Python’s strengths and it’s basically a straight port of a C algorithm.
And if that wasn’t enough—it’s also the slowest solution, as you’ll see in the next section where I’ll do some benchmarking on these three implementations.
After implementing the string reversal approaches I showed you in this tutorial I became curious about what their relative performance would be.
So I set out to do some benchmarking:
>>> import timeit >>> s = 'abcdefghijklmnopqrstuvwxyz' * 10 >>> timeit.repeat(lambda: reverse_string1(s)) [0.6848115339962533, 0.7366074129968183, 0.7358982900041156] >>> timeit.repeat(lambda: reverse_string2(s)) [5.514941683999496, 5.339547180992668, 5.319950777004124] >>> timeit.repeat(lambda: reverse_string3(s)) [48.74324739299482, 48.637329410004895, 49.223478018000606]
Well, that’s interesting…Here are the results in table form:
|reversed + join||5.39s||7.5x|
|Classic / In-Place||48.87s||67.9x|
As you can see, there’s a massive performance gap between these three implementations.
Slicing is the fastest approach,
reversed() is 8x slower than slicing, and the “classic” in-place algorithm is a whopping 71x slower in this benchmark!
Now, the in-place swap could definitely be optimized (leave a comment below with your improved solution if you want)—but this performance comparison still gives us a decent idea of which string reversal operation is the fastest in Python.
Summary: Reversing Strings in Python
String reversal is a standard operation in programming (and in coding interviews.) In this tutorial you learned about three different approaches for reversing a string in Python.
Let’s do a quick recap on each before I’ll give you my recommendation on which option I personally prefer:
Option 1: List Slicing Trick
You can use Python’s slicing syntax to create a reversed copy of a string. This works well, however it is slightly arcane and therefore not very Pythonic, in my opinion.
>>> 'TURBO'[::-1] 'OBRUT'
- Creates a reversed copy of the string
- This is the fastest way to reverse a string in Python
reversed() function allows you to create a reverse iterator for a Python string (or any sequence object.) This is a flexible and clean solution that relies on some advanced Python features—but it remains readable due to the clear naming of the
>>> ''.join(reversed('TURBO')) 'OBRUT'
reversed()returns an iterator that iterates over the characters in the string in reverse order
- This character stream needs to be combined into a string again with the
- This is slower than slicing, but arguably more readable
Option 3: “Roll Your Own” String Reversal
Taking the standard “in-place” character swap algorithm and port it to Python works, but it offers inferior performance and readability compared to the other options.
def reverse_string(s): """Return a reversed copy of `s`""" chars = list(s) for i in range(len(s) // 2): tmp = chars[i] chars[i] = chars[len(s) - i - 1] chars[len(s) - i - 1] = tmp return ''.join(chars) >>> reverse_string('TURBO') 'OBRUT'
- This is vastly slower than slicing or reverse iteration (depending on the implementation)
- Rolling your own string reversal algorithm is not recommended, unless you’re in a coding interview situation
If you’re wondering what the best way is to reverse a string in Python my answer is: “It depends.” Personally, I like the
reversed() approach because it’s “self-documenting” and reasonably fast.
However, there’s an argument to be made that the eight times faster slicing approach should be used for reasons of performance…
Depending on your use case, this might well be. And yet, this is also the perfect time for me to whip out Donald Knuth’s immortal quote:
“Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered.
We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
Yet we should not pass up our opportunities in that critical 3%.”
— Donald Knuth (Source)
For this reason, I wouldn’t start worrying about string reversal performance in your programs—unless it’s an integral part of what your software does. If you’re reversing millions of strings in a tight loop, by all means, do optimize for speed.
But for the average Python application it won’t make a perceptible difference. So I would go with the most readable (and therefore maintainable) approach.
In my books this is option 2:
If you’d like to dig deeper into the subject, be sure to watch my YouTube tutorial on list reversal in Python. Also, you’re welcome to leave a comment below to let me know about your favorite string reversal techniques. Happy Pythoning!