0

In the code below I expect it prints reach here 2, because none of the variable meets the conditions of the if statement However, the code prints reach here 1.

m = 1
type1 = 'a'
type2 = 'x'

if m > 1 and type1 == 'b' and type2 == 'y' or 'z':
    print('reach here 1')
elif type1 == 'a' and type2 == 'x':
    print('reach here 2')

May anyone explain how come the code is able to "reach here 1", and help me correct the if statement so that it prints reach here 1 only when m > 1 and type1 = 'b' and type2 equals to either 'y' or 'z'? Appreciate!

Consideration
  • 182
  • 1
  • 1
  • 12
  • `type1` is `a` which fails at first point – bigbounty Jul 18 '20 at 01:40
  • 3
    `type2 == 'y' or 'z':` isn't doing what you think it is doing. It's evaluating all the conditions to the left and then finally, it is evaluating `or 'z'` and since all non-empty strings are truthy, that is *always* True. – juanpa.arrivillaga Jul 18 '20 at 01:50
  • 3
    In everyday language we can ask "Is x equal to 41 or 42?", and it's understood that "Is x equal to ..." applies to both 41 and 42. But Python doesn't work that way. When it sees `type2 == 'y' or 'z'`, it sees `type2 == 'y'` on the left and `'z'` standing alone by itself on the right. Non-empty strings are always true, so `... or 'z'` is always true. – John Gordon Jul 18 '20 at 01:50

2 Answers2

1

And for the statement type2 == 'y' or 'z' this does not check if type2 is 'y' or 'z'. Instead you should use an in operator with the values as a list

In [19]: m = 1
    ...: type1 = 'a'
    ...: type2 = 'x'
    ...:
    ...: if m > 1 and type1 == 'b' and type2 in ["x","z"]:
    ...:     print('reach here 1')
    ...: elif type1 == 'a' and type2 == 'x':
    ...:     print('reach here 2')
    ...:
reach here 2
bigbounty
  • 16,526
  • 5
  • 37
  • 65
1

The reason that the 'reach here 1' statement is being triggered is because the first if condition is being evaluated to true.

Since you have no parentheses/grouping of the 'and' statements, if all three and statements are true or that one 'OR' statement is true, the first 'if' statement will be evaluated to true and 'reach here 1' will be printed.

In this case, the one 'OR' statement is true. Python is looking at the line

if m > 1 and type1 == 'b' and type2 == 'y' or 'z'

and saying, "Okay, m>1, check. type1 doesn't == b, so no, these AND statements are false. Then, it moves onto the OR statement and says is 'or Z' true.

In python, any non-empty string value is true. Thus, 'z' evaluates to TRUE and the OR condition is satisfied - thanks to @juanpa.arrivillaga for this correction. See this page for more info: Truth value of a string in python

Evan
  • 1,892
  • 2
  • 19
  • 40
  • 1
    " In this case, 'z' has a certain decimal value associated with it and thus represents a number which is non-zero" Um, no, that isn't how string truth-value testing works. *empty* strings are Falsy, all other strings are truthy, including `chr(0)`, so `if chr(0): print('hi')`. Types define their own boolean behavior, by default, any user-defined object is truthy. But you can, for example, override that with `__bool__`. Of the built-in types, numeric types which have a value of 0 are falsy, container types (includings strings) are falsy if they are empty. – juanpa.arrivillaga Jul 18 '20 at 01:51