Python testing whether a string is one of a certain set of values

I'm learning python on codecademy and my current task is this:

Write a function, shut_down, that takes one parameter (you can use anything you like; in this case, we'd use s for string). The shut_down function should return "Shutting down..." when it gets "Yes", "yes", or "YES" as an argument, and "Shutdown aborted!" when it gets "No", "no", or "NO".

If it gets anything other than those inputs, the function should return "Sorry, I didn't understand you."

Seemed easy to me but somehow I still can't do it.

My code I made to test the function:

def shut_down(s):
    if s == "Yes" or s == "yes" or s == "YES":
        return "Shutting down..."
    elif s == "No" or "no" or "NO":
        return "Shutdown aborted!"
    else:
        return "Sorry, I didn't understand you."

i = input("Do you want to shutdown?")
print(i) #was to test the input
print(shut_down(i)) #never returns "Sorry, I didn't understand you"

It works fine for the no's and yes', but somehow if I put a space before any yes or even if I just type in "a" it prints "Shutdown aborted!" although it should print "Sorry, I didn't understand you".

What am I doing wrong?


Solution 1:

You forgot to write s == "no" in your first elif:

def shut_down(s):
    if s == "Yes" or s == "yes" or s == "YES":
        return "Shutting down..."
    elif s == "No" or "no" or "NO":             # you forgot the s== in this line
        return "Shutdown aborted!" 
    else:
        return "Sorry, I didn't understand you."

Do this:

def shut_down(s):
    if s == "Yes" or s == "yes" or s == "YES":
        return "Shutting down..."
    elif s == "No" or s == "no" or s == "NO":       # fixed it 
        return "Shutdown aborted!"
    else:
        return "Sorry, I didn't understand you."

This is because:

elif s == "No" or "no" or "NO":  #<---this
elif s == "No" or True or True:  #<---is the same as this

Since this is the accepted answer I'll elaborate to include standard practices: The convention for comparing strings regardless of capitalization (equalsIgnoreCase) is to use .lower() like this

elif s.lower() == "no":

Solution 2:

Instead of checking for different combinations of capitalization you could uses the lower function to return a copy of s in lowercase and compare against that.

def shut_down(s):
    if s.lower() == "yes":
        return "Shutting down..."
    elif s.lower() == "no":       
        return "Shutdown aborted!"
    else:
        return "Sorry, I didn't understand you."

This is much cleaner and easier to debug. Alternatively you could use upper also and compare against "YES" and "NO".


If this doesn't help because of matching cases like nO then I'd go with the in statement:

def shut_down(s):
    if s in ("yes","Yes","YES"):
        return "Shutting down..."
    elif s in ("no","No","NO"):       
        return "Shutdown aborted!"
    else:
        return "Sorry, I didn't understand you."

Solution 3:

Python evaluates non empty strings to be True, so your elif condition is always evaluated to True.

>>> bool('No')
True

>>> bool('NO')
True

Doing a boolean or with a True value would always return True, so it never reaches the else condition and gets stuck on the elif one.

You need to test the conditions using.

elif choice == 'no' or choice == 'NO' or choice == 'No':

EDIT - As glglgl pointed out in the comment, == binds harder than or, so your condition gets evaluated as (s == 'No') or 'no' or 'NO' and not s == ('No' or 'no' or 'NO'), in which case you would have gotten to the else part even for a user input of 'NO'.