Skip to main content
5 of 7
added 27 characters in body
C.Nivs
  • 3.1k
  • 14
  • 32

You don't need the loop. Once i > 0, the if statement will always be False:

x = 'abba'
x[0::1] == x[::-1]
True

x[1::1] == x[::-1]
False

x[1::1]
'bba'

So drop the iteration. Besides, the immediate return won't allow for iteration anyways, a second iteration will never be reached:

def is_palindrome(x):
    x = x.lower()

    if x[::-1] == x:
        return f'{x} is a palindrome'
    else:
        return f'{x} is not a palindrome'

You don't need the parentheses with return, and I'd use f-strings instead of % formatting if you're on python 3.5+.

If you are adding the possibilities of spaces/punctuation, you could change x to only include alphabet chars:

def is_palindrome(x):
    # this will produce only alphabet lowercase chars
    # and join them into a string, though I'm not sure if
    # this is a use case for you
    x = ''.join(filter(str.isalpha, x.lower()))

    if x[::-1] == x:
        return f'{x} is a palindrome'
    else:
        return f'{x} is not a palindrome'

To show what that join statement does:

# maybe this should be a palindrome if you ignore the
# non-alpha chars including spaces
x = "ABC1234CB a."

y = ''.join(filter(str.isalpha, x.lower()))
'abccba'

Edit

To address concerns in the comments, if you wanted to offer options into what kind of filtering you want to provide, you could use a dictionary to act as a mapping:

from functools import partial

def is_palindrome(input_str, filter_type='nofilter'):
   """
   Parameter 'filter_type' defaults to pass-through, but you can
   provide options such as 'alphanum', 'nospace' (to just get rid of spaces), and 'alpha'
   """
   filters = {
       'alpha': partial(filter, str.isalpha),
       'alphanum': partial(filter, str.isalnum),
       'nospace': partial(filter, lambda char: not char.isspace()),
       'nofilter': partial(map, lambda char: char) # this is just a pass-through 
   }

   # raise this exception just so the use is more clear to the user
   # what is expected
   try:
       f = filters[filter_type]
   except KeyError as e:
       raise ValueError(
           f"Invalid filter_type, choose one of {'\n'.join(filters)}"
       ) from e

   x = ''.join(filter_type(input_str.lower()))

   # you can just check the first half of the string
   # against the last half reversed, rather than comparing the entire string 
   midpoint = len(x) // 2
   if len(x) % 2: # even length
       a = b = midpoint
   else:
       a, b = midpoint + 1, midpoint

   return x[:a] == x[b::-1]

partial will bind arguments to a function and return a new callable. As a small example:

def f(a):
    return a

g = partial(f, 1)
f(2)
2

g()
1

Which is helpful for taking a function that takes many arguments and returning one that takes fewer arguments.

Credit to Toby Speight for returning bool type, @Baldrickk for midpoint slice, and @Peilonrayz for concern over input filtering.

C.Nivs
  • 3.1k
  • 14
  • 32