Python if/else defers to wrong branch - python

I'm writing an Interactive Fiction game for a school project, and for some reason, when I try to use an if/else statement with input (or raw_input), the if else statement defers to the wrong branch regardless of what I input. Here is the code in question:
print( """
You enter the room to the south.
Upon entering you mark that it is pitch black,
and if you were in the famous text adventure Zork,
you would be likely to be eaten by a grue. Thank
the programmer for small favors. Unlike in that game,
you have a candle, a single stick of 100-year-old
dynamite, and that matchbook from earlier.
You just knew that would be useful! The candle and
the dynamite have the same shape, size, and weight.""")
choice1 = True
while choice1 == True:
choice2 = input("Will you strike a match? ")
if choice2 == "Yes" or "yes" or "y":
print("""
It flickers for a second. You can kind of make
out which is which, but alas! They are both
covered in red paper! You are beginning to sweat
from the nervousness.""")
choice1 = False
elif choice2 == "No" or "no" or "n":
print("""
Okay. I can wait, you aren’t leaving this room until
you light a match. You will eventually light a match,
but I can wait until you do.""")
choice1 = True
else: choice1 = True
The if/else statement is treating anything that I type as though I typed yes. Can anyone help me with this error?

Your if statements are wrong, they should look like this:
if choice in ["Yes", "yes", "y"]:
…
or like this:
if choice == "Yes" or choice == "yes" or choice == "y":
…
Python treats an non-empty string as true, e.g. "Yes" is considered true. So if you write choice == "yes" or "Yes", the expression is always true because if even if choice == "yes" isn't true, "Yes" will be considered true.

I believe your problem is in the if statements' conditionals, such as if choice2 == "Yes" or "yes" or "y". This looks like it would check whether choice2 is "Yes" or choice2 is "yes" or choice2 is "y", but it doesn't. The problem is the or statement. The if statement in your code could be written as if (choice2 == "Yes") or ("yes") or ("y") and have the same meaning. This makes it easier to see that, even if choice2 does not equal Yes, the expression will be true because the string "yes" is non-empty and as thus is converted to True in an if statement. This is because the or operator in python is a boolean OR, so if either side of the operator, converted to a boolean, is true, then the expression is. The easiest (i.e. least code refactoring) way to fix this is a series of =='s:
if choice2 == "Yes" or choice2 == "yes" or choice2 == "y": #...
There are others, but this should do the trick for a simple-is program like yours. If you need to do more and more complex matching, you should look into string operators. FOr example, your expression could be rewritten as if "yes".startswith(choice2.lower()): #..., but don't use this without understanding it. For a program of the size of yours, the chained =='s will do just fine. Hope this helps!

The line if choice2 == "Yes" or "yes" or "y" doesn't work like you think it does. After the first statement choice2 == "Yes" it is like asking if "yes" or if "y". The if statement on a string will always return true, unless it is an empty string. To fix this you'll need either
if choice2 == "Yes" or choice2 == "yes" or choice2 == "y":
or this more pythonic approach:
if choice2 in ["Yes", "yes", "y"]:
which will check if the string is in that array.
Of course the same thing applies to elif choice2 == "No" or "no" or "n":, which in its current form will also always return true.

Related

Python and vs or in while loop

choice = input('Enjoying the course? (y/n)')
while choice != "y" or choice != "n":
choice = input("Sorry, I didn't catch that. Enter again: ")
im trying to understand why the code above doesnt exit the while loop if i input 'y' or 'n', but if i change the or to and and input 'y' or 'n' the while loop exits? To my understanding it should have worked both.
In or case its read as
while choice is not 'y' or choice is not 'n' -> exit
just like and
while choice is not 'y' and choice is not 'n' -> exit
You should use and instead of or:
while choice != "y" and choice != "n":
choice = input("Sorry, I didn't catch that. Enter again: ")
choice != "y" or choice != "n" always evaluates to True since choice cannot be y and n at the same time.
while choice != "y" or choice != "n":
choice = input("Sorry, I didn't catch that. Enter again: ")
You want the while loop to repeat
until choice equals "y" or choice equals "n"
So you want it to last
while choice doesn't equal "y" and choice doesn't equal "n"
So the correct code in your case would be
while choice != "y" and choice != "n":
Note
In Python a better practice would be writing this
while choice not in ("y", "n"): # Easier to understand, right?
Look at it this way:
if you enter "y" on or operator below happens
while "y" != "y" or "y" != "n":
which translates to below
while False or True:
and its or operator so (True or False) will always be True
if you enter "y" on and operator below happens
while "y" != "y" and "y" != "n":
which translates to below
while False and True:
and as its and operator so (True and False) will always be False
hence you should use and if you want to leave the loop
There are exactly 3 cases:
source is 'x'
source is 'y'
source is something else. Not one of {'x', 'y'}.
In all of these 3 states the OR condition holds, and therefore the loop continues.
In other words, the condition is always True, because choice can be only one of the two values. And therefore it is always not one of them, at least. Hence, the OR condition always holds, and the loop continues.

Why is my if-elif-else statement always returning the same answer? [duplicate]

This question already has answers here:
How to test multiple variables for equality against a single value?
(31 answers)
Closed 1 year ago.
Background:
I'm experimenting with while loops and I just made a simple program nested in a while loop.
Code:
while True:
userinput = input("Is nem jeff? ")
if userinput == "y" or "yes" or "Y" or "Yes":
print ("YAY!")
elif userinput == "n" or "no" or "N" or "No":
print ("das sad :(")
else:
print ("wrong input")
break
Problem:
My program should be looping until the user types in an invalid input, but instead, it always returns the value nested in the if statement, no matter what I type in. What am I doing wrong?
Your conditionals aren't doing what you think they are.
In Python, a non-zero-length string evaluates to True in a boolean
context. The or operator performs a boolean or operation between
the lefthand operand and the righthand operand.
So when you write this:
if userinput == "y" or "yes" or "Y" or "Yes":
What you are saying is this:
if (userinput == "y") or True or True or True:
Which will always evaluate to True. You want to write instead:
if userinput == "y" or userinput == "yes" or userinput == "Y" or userinput == "Yes":
Or more simply:
if userinput.lower() in ['y', 'yes']:
The reason false down to truthsy or falsy in if conditions.
based on your initial code block
print('y'=='yes'or'y')
[output] y
print('n'=='yes'or'y')
[output] y
based on the above you can see that regardless of you input, your first if statement would be evaluated as True.
rather than doing that, try doing this instead.
while True:
userinput = input("Is nem jeff? ").lower()
if userinput in ['yes','y']:
print ("YAY!")
elif userinput in ['no','n']:
print ("das sad :(")
else:
print ("wrong input")
break

Checking input against a list in python - why does one way work while the other doesn't?

Started learning python a few days ago and was doing a task with simple yes/no inputs and doing different things with the while loop depending no whether the user wants to continue using the program or not.
The whole program is fairly small so hope it's alright to post the entirety of its code here. This is what worked for me:
import random
print("=====================================")
print("I Add Numbers and Tell You the Sum v2")
print("=====================================")
while True:
rand1 = random.randint(1, 100)
rand2 = random.randint(1, 100)
result = rand1 + rand2
print(f"I'm adding {rand1} and {rand2}. If you add them together,the result would be {result}")
print()
again_input = input("Would you like to try again? (Y/N) ")
again = again_input.lower().strip()
validyes = ["yes", "y"]
validno = ["no", "n"]
if again in validyes:
print("Sure thing!")
print()
elif again in validno:
print("Okay. See you!")
break
else:
print("That's not a valid response. The program will now exit.")
break
While the relevant code that didn't work as expected was this, to do with checking the user input against the valid list:
valid = ["yes", "y", "no", "n"]
if valid == "yes" or "y":
print("Sure thing")
elif valid == "no" or "n":
print("Okay bye")
break
else:
print("That's not a valid response. The program will now exit")
break
The former would run just fine, while the latter will print "Sure thing" regardless of what the user inputs. Why is that the case?
On that front, I'm happy to hear any other tips you guys might have with regards to making the rest of the code better. Eager to hear from and take part in this community!
You have to show what all the string what they are comparing to
if again == "yes" or again == "y":
print("Sure thing")
elif again == "no" or again == "n":
print("Okay bye")
break
else:
print("That's not a valid response. The program will now exit")
break
Also a tip is to use "\n" for a new line. The \n will not be shown
Old:
print(f"I'm adding {rand1} and {rand2}. If you add them together,the result would be {result}")
print()
New:
print(f"I'm adding {rand1} and {rand2}. If you add them together,the result would be {result}\n")
Last is that for the lower and strip function u can use it in the same line were u get your input
Old:
again_input = input("Would you like to try again? (Y/N) ")
again = again_input.lower().strip()
New:
again = input("Would you like to try again? (Y/N) ").lower().strip()
In the second case you're using the OR operand wrong and that's why it is always printing Sure thing. Here you can take a look and understand it better.
To make the code better, i would suggest keeping the valid list with all valid inputs, and checking for yes or no using the if again in valid method, but playing with what is and isn't valid inputs.
This is how or works
operation: x or y result: if x is false, then y, else x
Explanation:
valid == "yes" will be false for obvious reason because you are comparing a list to a string. When the first condition is false operator or goes to evaluate next condition which is just "y" and will always be true(you can confirm it using bool("y")) so that's why it's always printing "Sure thing".
You use this:
if valid == "yes" or "y":
print("Sure thing")
elif valid == "no" or "n":
print("Okay bye")
break
So in the first condition you check if (valid == "yes") or ("y"), but not if valid == ("yes" or "y"). Non-empty string is always True, when you use it as bool, so the first condition is always True. If you want to do somwthing like this, you can use tuples (it's like lists, but you cant edit it): if valid in ("yes", "y")
valid is a list, so valid will never equal to "yes", so it just goes to "y", which will always equal true. You need to check if "yes" or "y" is in valid:
if "yes" in valid or "y" in valid:
print("Sure thing")
elif "no" in valid or "n" in valid:
print("Okay bye")
break
Of course, with this code it will always print "Sure thing" because valid includes all the options.

Python Input Function

I was wondering if somebody could tell me what is wrong with this code, when I run the code it shows nothing but if I take out the "elif" it does work.\
first=input("What is your first name? ");
middle=input("What is your middle name? ");
last=input("What is your last name? ");
test = [first, middle, last];
print ("");
print ("Firstname: " + test[0]);
print ("Middlename: " + test[1]);
print ("Lastname: " + test[2]);
print ("");
correct=input("This is the information you input, correct? ");
if (correct == "Yes" or "yes"):
print ("Good!")
elif (correct == "no" or "No"):
print ("Sorry about that there must be some error!");
Here's the problem:
if (correct == "Yes" or "yes"):
# ...
elif (correct == "no" or "No"):
# ...
It should be:
if correct in ("Yes", "yes"):
# ...
elif correct in ("No", "no"):
# ...
Notice that the right way to make a comparison involving several conditions is like this:
correct == "Yes" or correct == "yes"
But usually it gets written like this, which is shorter:
correct in ("Yes", "yes")
You need to use the in keyword:
if correct in ("Yes", "yes"):
print ("Good!")
elif correct in ("no", "No"):
print ("Sorry about that there must be some error!")
or convert the entire input to the same case:
# I use the lower method of a string here to make the input all lowercase
correct=input("This is the information you input, correct? ").lower()
if correct == "yes":
print ("Good!")
elif correct == "no":
print ("Sorry about that there must be some error!")
Personally, I think the lower solution is the cleanest and best. Note however that it will make your script accept inputs such as "YeS", "yEs", etc. If this is a problem, go with the first solution.
You'e checking correct incorrectly
if (correct == "Yes" or "yes"):
means (correct == "Yes") or ("yes"), and non-empty string evaluates to True in python, so first condition will always be True.If you want to check multiple strings, you can do:
if (correct in ("Yes", "yes")):
But this one doesn't takes 'yEs' or 'yES' into account. If you want case-insensitive comparison, then I think correct.lower() == "yes" would be preferred method.

If-branch for x == "N" or "No" always runs [duplicate]

This question already has answers here:
Why does "a == x or y or z" always evaluate to True? How can I compare "a" to all of those?
(8 answers)
Closed 6 months ago.
When I run this in my program, the question goes through, however no matter the answer, the "No" option always runs. If I switch the option order, the "Y" option will only run and it will always go straight to start. I'm sure I'm missing something simple, I just don't know what.
infoconf = raw_input("Is this information correct? Y/N: ")
if infoconf == "N" or "No":
print "Please try again."
elif infoconf == "Y" or "Yes":
start()
else:
print "That is not a yes or no answer, please try again."
Supposed to be
infoconf = raw_input("Is this information correct? Y/N: ")
#you wrote: infoconf == "N" or "No" but should be:
if infoconf == "N" or infoconf == "No":
print "Please try again."
#you wrote: infoconf == "Y" or "Yes" but should be
elif infoconf == "Y" or infoconf == "Yes":
start()
else:
print "That is not a yes or no answer, please try again."
Short explanation:
when value of x = 'N'
x == 'N' or 'No' will return True
when value of x = 'Y'
x == 'N' or 'No' will return 'No' i believe this is not what you want
at the other side
when value of x = 'N'
x == 'N' or x == 'No' will return True
when value of x = 'Y'
x == 'N' or x == 'No' will return False i believe this is what you want
Python will interpret infoconf == "N" or "No" differently than you thought. This is somewhat a case of "operator precedence" where your condition is parsed as (infoconf == "N") or ("No").
Now, infoconf == "N" may or may not be true, but "No" is "something" and when treated as a logical evaluates as true. In effect, your condition infoconf == "N" or true will always be true.
As many others suggested, comparing infoconf to "No" in your second logical term will do the trick.
Personally I'd do something like this:
infoconf = raw_input("Is this information correct? Y/N: ")
if infoconf.lower().startswith('n'):
# No
elif infoconf.lower().startswith('y'):
# Yes
else:
# Invalid
This means that the user could reply "Y/y/yes/yeah" for yes, and "N/n/no/nah" for no.
In Python, it's a bit easier to do this as:
infoconf = raw_input("Is this information correct? Y/N: ")
if infoconf in ["N", "No"]:
print "Please try again."
elif infoconf in ["Y", "Yes"]:
start()
else:
print "That is not a yes or no answer, please try again."
As others have said, if infoconf == "N" or "No" is equivilent to if (infoconf == "N") or "No", and since "No" (as a non-empty string) evaluates to True, the statement will always be true.
Also, to be a little less picky on the input, you might want to do infoconf = infoconf.strip().lower() before you do the tests (and then compare to the lower case versions).

Categories

Resources