Time for another Python challenge. This time it’s the palindrome challenge. What is a palindrome? A palindrome is a word, number, phrase, or other sequence of characters which reads the same backward as forward. Some examples are level, radar, stats.
The goal is to take a string the user inputs, reverse the string and see if it’s identical backward as forward. I will divide my code into two functions:
- get_string
- check_palindrome
The first function simply takes the string that is input. The second function checks if it’s a palindrome and prints the result.
As always, let’s first start with a docstring:
"""Program to check if string is a palindrome"""
Then we create a function to get the string from the user. This code should look familiar if you went through the divisors challenge.
def get_string(): """Get a string from user to be used in function to check for palindrome""" # Get string from user with input() and return result user_string = input("Please enter a string to check if it's a palindrome: ") return user_string
Now for the more interesting part, to check if a string is a palindrome. To do that, we need to reverse the string. How can we do that? The easiest way is probably to use slicing. Let’s give an example using the REPL:
First we create a string, the word radar:
daniel@devasc:~/DevAsc$ python3 Python 3.8.2 (default, Apr 27 2020, 15:53:34) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> word = "radar" >>>
If we want to access a specific letter of this word, we can use access it by index. For example, to access the first letter:
>>> word[0] 'r'
Notice that counting starts from from zero. If we want to access the last letter, it is accessible at -1
:
>>> word[-1] 'r'
We can also access a range of letters, a slice
, by specifying a start
and stop
with a colon in between. For example, the three first ones, with a range from 0
to 3
, because the stop
index is not inclusive:
>>> word[0:3] 'rad'
It’s also possible to use a stepping
. What if we want to access the entire string but only every other letter? We can do that by specifying 0:6:2
. Start at index 0
, stop at 6
not inclusive, with a stepping
of 2
.
>>> word[0:6:2] 'rdr'
The drawback here though is that this is not a generic approach since we have specified the stop
manually. There are defaults when using slicing that we can leverage to write this more efficiently. The defaults, when using a positive stepping
, are these:
- Start at index 0
- End where the string ends
- Stepping of 1
This means that we can access the slice with ::2
, where we are using the default values for start
and stop
, as indicated by the colon, meaning to start at 0
and end where the string ends.
>>> word[::2] 'rdr'
Awesome! So how do we then find the reverse of a string? The trick is to use a negative stepping
. This is where things can get a bit confusing. When using a negative stepping
, the defaults for start
and stop
change. The defaults are then these:
- Start at the end of the string
- Stop at the beginning of the string
This means that we can reverse a string by using ::-1
where the first colon means to start at the end of string, go to the start of the string, with a stepping of -1
, that is, go one step backward each time.
>>> word[::-1] 'radar'
Great. Now let’s write this as a function:
def check_palindrome(user_string): """Reverse string from user and check if palindrome""" user_string_reverse = user_string[::-1] if user_string_reverse == user_string: print("It's a palindrome!") else: print("It's NOT a palindrome!")
We store the user_string
in reverse in user_string_reverse
. Then we check if they are equal. If they are, it’s a palindrome!
We must, of course, run the functions:
if __name__ == "__main__": user_string = get_string() check_palindrome(user_string)
When we run the code, this is what it looks like:
l@devasc:~/DevAsc$ python3 palindrome.py Please enter a string to check if it's a palindrome: radar It's a palindrome! daniel@devasc:~/DevAsc$ python3 palindrome.py Please enter a string to check if it's a palindrome: boat It's NOT a palindrome! daniel@devasc:~/DevAsc$
Finally, here’s the entire code:
"""Program to check if string is a palindrome""" def get_string(): """Get a string from user to be used in function to check for palindrome""" # Get string from user with input() and return result user_string = input("Please enter a string to check if it's a palindrome: ") return user_string def check_palindrome(user_string): """Reverse string from user and check if palindrome""" user_string_reverse = user_string[::-1] if user_string_reverse == user_string: print("It's a palindrome!") else: print("It's NOT a palindrome!") if __name__ == "__main__": user_string = get_string() check_palindrome(user_string)
It is available via Github as well.
Bonus: There’s another way of solving this challenge, with a For loop, although slicing is the preferred method. It looks like this:
daniel@devasc:~/DevAsc/Python-challenges$ python3 Python 3.8.2 (default, Apr 27 2020, 15:53:34) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> word = "radar" >>> reverse = "" >>> for i in range(len(word)): ... reverse += word[len(word)-1-i] ... >>> print(reverse) radar >>>
We have the string radar stored in word
. We also have an empty string called reverse
. We can iterate through word
. To do this, we use a for loop that loops through range(len(word))
, that is, the length of the word.
We then add letters to reverse
, starting at the end. Why do we have len(word)-1
? Because of the zero index. Otherwise we would try to access an index that is not available. Why -i
at the end? So that we move towards the start of the string. Note that the iterator is 0
when it starts, then it’s 1
, 2
, 3
, and so on.
Happy coding!