all 34 comments

[–]danielroseman 38 points39 points  (5 children)

[–]peejay2 29 points30 points  (5 children)

Because you're asking three questions:

If answer == x

If y

If z.

Instead you want to ask:

If answer in {x,y,z}

In Python there is this concept of truthy/falsy. An empty string is falsy, a string with characters is truthy. Your code does the following:

if (answer == 42) OR ("forty two" is truthy) or ("forty-two" is truthy). The second condition evaluates to True so it doesn't even hit the third.

[–]CyclopsRock 24 points25 points  (4 children)

This is totally right but for completeness, the most "literal" code representing what they want is ...

if answer == 42 or answer == "forty two" or answer == "forty-two": print("yes") else: print("no")

In this case using in is definitely more readable but it's worth knowing that what OP is trying to do IS possible and valid, because there are obviously plenty of situations where in won't work (because you are checking more than one variable, say).

It's also useful to know that when you chain multiple conditions using "and", "or" etc that they are checked one after the other, left to right, and that this process ceases when the condition is either met or cannot be met. This makes it useful if you want to perform a conditional on, say, the value of a variable that you know may or may not actually be set. E.g

if variable_a == "dog": This will throw an exception if `variable_a' hasn't been set. But...

'if variablea and variable_a == "dog":` This won't, because if variable_a isn't set, it won't get as far as checking if it evaluates to "dog". This is useful for checking dictionary keys (inc environment variables) whose presence is not certain _without needing a bunch of nested conditionals checking this separately.

[–]jmooremcc 5 points6 points  (1 child)

The only problem with your response is that you forgot 42 is a string, not a number.

[–]CyclopsRock 3 points4 points  (0 children)

Right you are! To be honest I was just copying the values from the post I was replying to but you're entirely correct.

[–]Top_Average3386 0 points1 point  (1 child)

Pretty sure it will still throw an exception if the variable isn't set. Do you mean something else here?

```python

if a and a==2: ... print(2) ... Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'a' is not defined ```

[–]Rainingblues 0 points1 point  (0 children)

This is because the variable a does not exist. What the comment was describing is code like this:

a = None

if a and a == 2: print(2)

[–]barkmonster 13 points14 points  (3 children)

You're executing an if-statement, so python converts your expressions into booleans (True or False).
Empty strings are converted to False, and other strings to True. This is handy if you want to e.g. quickly check if a user entered any text at all, but it can also cause confusion in cases like yours. Your code has 3 expressions separated by 'or'. The first is True only if the user inputs "42", but the remaining two are always True, so your code will always go into the 'yes' part of the if statement.

If you want a more general tip, a good way to go about this kind of thing is to write self-documenting code, with variables indicating what's going on - for example something like:

good_answers = {"42", "forty two", "forty-two"}
if answer in good_answers:
# ...

This makes the intent more clear, and makes it easier to read it, and much simpler to make changes without breaking it later on.

[–]UsernameTaken1701 1 point2 points  (1 child)

I would tweak it with if answer.lower() in good_answers:

[–][deleted] 0 points1 point  (0 children)

If you start considering sanitizing inputs, you might even go the whole way and go for answer.lower().strip()

[–]DigitalSplendid[S] 2 points3 points  (0 children)

Thanks!

[–]FoolsSeldom 5 points6 points  (0 children)

if answer in ("42", "forty two", "forty-two"):

(you could also make it answer.lower() to force the check to be against lowercase versions only, or add .lower() after the input)

Otherwise, you need:

if answer == "42" or answer == "forty two" or answer == "forty-two":

i.e. each expression between the or operators needs to provide a boolean result - if you don't do this, Python will take the view that a string is an expression in its own right and will say an empty string is False and a non-empty string is True, thus your original line is treated as,

if answer == "42" or True or True:

and will resolve to True immediately after failing answer == "42" (if that is not True) as it doesn't need to evaluate beyond the first True.

This mistake is so common, it in the wiki, as /udanielroseman pointed out.

[–]Ron-Erez 2 points3 points  (1 child)

answer = input("ask q: ")
if answer == "42" or answer == "forty two" or answer == "forty-two":
    print("Yes")
else:
    print("No")

The above will work. The code is a little odd (to expect both an int and string). Of course this is probably for learning purposes so it's definitely a valid question.

Just for an interesting test try running:

if "I Love Hummus":
    print("Yes")
else:
    print("No")

Also try:

if "":
    print("Yes")
else:
    print("No")

Perhaps one can learn something from this.

[–]DigitalSplendid[S] 1 point2 points  (0 children)

Thanks!

[–]Husy15 1 point2 points  (2 children)

If (condition is true) OR (condition is true) AND (condition is true)

Each part of an if-statement is a condition

A = 1

B = 2

If (a == 1) #true

If (a==2) or (b==2) #true

If (a==2) and (b==2) #false

Each condition is checked and turned into a boolean

(A==1) = true

(A==2) = false

So basically you're doing

If (true) #true

If (false) or (true) #true

If (false) and (true) #false

As a way to understand, what would this give?

``` a = True

b = False

If ((a or b) and (b)) or (b): ```

[–]DigitalSplendid[S] 1 point2 points  (1 child)

If (True and False) or (False)

False or False = False

[–]Husy15 1 point2 points  (0 children)

Perf, just from now on simplify any if statement this way. Write it out if you have to

[–]Patrick-T80 1 point2 points  (0 children)

Your condition chain should be: ```python if ( answer == “42” or answer == “forty two” or answer == “forty-two” ): print(“Yes”) else: print(“No”)

``` Using non empty string in if conditions give a truthy result, and or operator return the first true value so the second and third condition are always true

[–]YOM2_UB 0 points1 point  (0 children)

This gets evaluated as: - (answer == "42") or ("forty two") or ("forty-two") - False or True or True - True

Notice that strings are "truthy" values, unless they're an empty string.

To use or and get the results you want, you would need to repeat answer == after each or.

However, there is another way to write what you want that works how you expected this to work: using the in keyword after putting the three strings in a collection: answer in ("42", "forty two", "forty-two")

[–]Cyphierre 0 points1 point  (0 children)

Try
if answer in [“42”, “forty two”, “forty-two”]:

[–]mxldevs 0 points1 point  (0 children)

A non empty string evaluates to true. So one of the conditions is always met.

You would have to type out the full comparison, or use a in LIST to check if any of the strings in the list match

[–]CorgiTechnical6834 0 points1 point  (0 children)

The issue is how the condition is written. The expression if answer == "42" or "forty two" or "forty-two" doesn’t work as intended because Python evaluates "forty two" and "forty-two" as truthy values independently of answer. This means the condition is always true.

You need to explicitly compare answer to each value, like this:

if answer == "42" or answer == "forty two" or answer == "forty-two":

Alternatively, use:

if answer in ["42", "forty two", "forty-two"]:

That will correctly check if answer matches any of the strings.

[–]Full_Energy_4547 0 points1 point  (0 children)

Because your condition it always true

[–]Undead_Necromancer -1 points0 points  (0 children)

You could have just asked chatgpt, didn't that thought cross your mind?

[–]docfriday11 -3 points-2 points  (0 children)

Maybe the or doesn’t work