0
def foo1():
   return True == 3 in [1,2,3]

def foo2():
    return 3 in [1,2,3] == True

def foo3():
     return True == ( 3 in [1,2,3] )

def foo4():
   return ( 3 in [1,2,3] ) == True 


foo1() => False
foo2() => False
foo3() => True
foo4() => True


import dis

dis.dis(foo1)

  2           0 LOAD_CONST               1 (True)
              2 LOAD_CONST               2 (3)
              4 DUP_TOP
              6 ROT_THREE
              8 COMPARE_OP               2 (==)
             10 JUMP_IF_FALSE_OR_POP    18
             12 LOAD_CONST               5 ((1, 2, 3))
             14 COMPARE_OP               6 (in)
             16 RETURN_VALUE
        >>   18 ROT_TWO
             20 POP_TOP
             22 RETURN_VALUE


dis.dis( foo2 )
  2           0 LOAD_CONST               1 (3)
              2 LOAD_CONST               2 (1)
              4 LOAD_CONST               3 (2)
              6 LOAD_CONST               1 (3)
              8 BUILD_LIST               3
             10 DUP_TOP
             12 ROT_THREE
             14 COMPARE_OP               6 (in)
             16 JUMP_IF_FALSE_OR_POP    24
             18 LOAD_CONST               4 (True)
             20 COMPARE_OP               2 (==)
             22 RETURN_VALUE
        >>   24 ROT_TWO
             26 POP_TOP
             28 RETURN_VALUE


>>> dis.dis( foo3 )
  2           0 LOAD_CONST               1 (True)
              2 LOAD_CONST               2 (3)
              4 LOAD_CONST               5 ((1, 2, 3))
              6 COMPARE_OP               6 (in)
              8 COMPARE_OP               2 (==)
             10 RETURN_VALUE


>>> dis.dis( foo4 )
  2           0 LOAD_CONST               1 (3)
              2 LOAD_CONST               5 ((1, 2, 3))
              4 COMPARE_OP               6 (in)
              6 LOAD_CONST               4 (True)
              8 COMPARE_OP               2 (==)
             10 RETURN_VALUE

From the disassemble code I can see the foo1() should return False since it won't execute the in comparison and hence False.

But what happens to foo2(), why does this return False?

Whereas foo3() and foo4() works perfectly as we can be confirmed from the disassembled code.

Ref: https://docs.python.org/2/library/dis.html

Python2.7

I've seen similar behavior python3+; the disassembled code is different but logic seems to be same in the disassembled code.

Python operator precedence: https://docs.python.org/2/reference/expressions.html#operator-precedence

Operator precedence for== and in is same but it doesn't match the expectation.

sonus21
  • 5,178
  • 2
  • 23
  • 48

1 Answers1

3

Both in and == are relation operators, and relational operators in Python chain. 3 in [1, 2, 3] == True performs both 3 in [1, 2, 3] and [1, 2, 3] == True simultaneously.

But you shouldn't be comparing against booleans regardless. Pass the result to bool() if you need to, but in already results in a boolean.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358