4
\$\begingroup\$

I am writing a python3 implementation of palindromes checker.

import string


def is_palindrome(text):
    """A string of characters is a palindrome if it reads the same forwards and
    backwards, ignoring punctuation, whitespace, and letter casing"""
    # implement is_palindrome_iterative and is_palindrome_recursive below, then
    # change this to call your implementation to verify it passes all tests
    assert isinstance(text, str)
    return is_palindrome_iterative(text)
    # return is_palindrome_recursive(text)

def is_palindrome_iterative(text):
    word = text

    # if the word[index] is not the same, return False
    # iteration through the index from  the half of the length
    # doing it through 
    for index in range(len(word)//2):
        if word[index] != word[-1-index]:
            return False
    return True




def main():
    import sys
    args = sys.argv[1:]  # Ignore script file name
    if len(args) > 0:
        for arg in args:
            is_pal = is_palindrome(arg)
            result = 'PASS' if is_pal else 'FAIL'
            str_not = 'a' if is_pal else 'not a'
            print('{}: {} is {} palindrome'.format(result, repr(arg), str_not))
    else:
        print('Usage: {} string1 string2 ... stringN'.format(sys.argv[0]))
        print('  checks if each argument given is a palindrome')


if __name__ == '__main__':
    main()

I think it works well.

ran python3 palindromes.py 'ABA' output is PASS: 'ABA' is a palindrome

\$\endgroup\$
  • 1
    \$\begingroup\$ Are you writing this specific implementation for a reason? I ask because your whole code (~42 lines) can be written as print(arg == arg[::-1]) \$\endgroup\$ – DeepSpace Oct 30 '17 at 11:43
  • \$\begingroup\$ Follow-up question \$\endgroup\$ – 200_success Oct 30 '17 at 16:45
6
\$\begingroup\$

1

I personally like to reduce the amount of string assembling where possible, so instead of:

result = 'PASS' if is_pal else 'FAIL'
str_not = 'a' if is_pal else 'not a'
print('{}: {} is {} palindrome'.format(result, repr(arg), str_not))

I would write:

PASS_TMPL = "PASS: {!r} is a palindrome"
FAIL_TMPL = "FAIL: {!r} is not a palindrome"
s = (PASS_TMPL if is_pal else FAIL_TMPL).format(arg)

In your example you had 3 variables in the string, in my example it's reduced to just 1 variable and 2 different templates.

of-course in this small program probably it doesn't matter which style you use. However if you build larger application the later style will bring you a few benefits:

  • output is more easily predictable
  • easier to change the output string without having a need to refactor the code
  • when debugging, and having to find location in code which produced certain output, it will be easier to grep the code for the specific string in question, if there is less string assembling going on.
  • if you need to add i18n support for your application at some point in time, you will learn that the way you assembled the strings only works in english, and your code needs to be refactored in order to support other languages

Because both styles usually are equally easy to code, avoiding the first style and preferring the 2nd style I think is a good habit to pick up.

2

Instead of the for loop to compare every individual letter, you can compare if the word is equal reversed version of it:

return word == word[::-1]
  • word[::-1] will reverse the word

This is not only shorter to write, but also in interpreted languages like python should run much faster too. A simple loop in python is very slow compared to a simple loop in C. String comparison will use compiled C implementation instead of looping each letter in python's loop.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.