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.