4

This question is asked out of purely curiosity/academic interest of Python as a language.

Suppose I have the following snippet:

>>> 1 in [1,2] == False
False

Which come out as expected as in takes precedence over == and 1 in [1,2] evaluates to True, and True != False.

But behold:

>>> 10 in [1,2] == False
False

Which is surprising because 10 in [1,2] evaluates to False and False == False should evaluates to True.

And I can prove that it is not because == is evaluated first, because it wouldn't even run:

>>> 10 in ([1,2] == False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: argument of type 'bool' is not iterable

While if in statement is run first by parenthesis it will return True:

>>> (10 in [1,2]) == False
True
# Note: All of above work in the same way if numbers and list are substituted by variables.

I went to dis and discovered an interesting caveat:

def func(): return (x in y == False)
dis.dis(func)

          0 LOAD_FAST                0 (x)
          2 LOAD_FAST                1 (y)
          4 DUP_TOP
          6 ROT_THREE
          8 COMPARE_OP               6 (in)
         10 JUMP_IF_FALSE_OR_POP    18
         12 LOAD_CONST               1 (False)
         14 COMPARE_OP               2 (==)
         16 RETURN_VALUE
    >>   18 ROT_TWO
         20 POP_TOP
         22 RETURN_VALUE

The JUMP_IF_FALSE_OR_POP bytecode entirely skips the == part (to 18) if FALSE. However, doing x in y == True also always evaluate to True on essentially the same bytecode. What's more, This bytecode is not seen in either in or == operations, something has to be generating it.

So what exactly is going on here? Why does everything in the format of x in y == (bool) Always evaluate to False? And what's actually happening behind the scene?

Rocky Li
  • 5,641
  • 2
  • 17
  • 33
  • Chaining comparison operators: have a look at `1 in (1, 2) == (1, 2)`. In general, if you're using this for an `if` statement and the like you can just rely on the truthiness of the comparison instead of comparing it to `False` manually – Patrick Haugh Feb 14 '19 at 02:19
  • Good find -- perfect answer. – Rocky Li Feb 14 '19 at 02:25
  • **x < y < z is equivalent to x < y and y < z, and is evaluates from left-to-right.** Going off of that logic your expression without brackets is: `1 in [1,2] and [1,2] == False` – cullzie Feb 14 '19 at 02:27

0 Answers0