Python's in (__contains__) operator returns a bool whose value is neither True nor False
boolean, comparison-operators, membership, python
Solution
You are running into comparison operator chaining; `1 in () == False` does not mean `(1 in ()) == False`.
Rather, comparisons are chained and the expression really means:
(1 in ()) and (() == False)
Because `(1 in ())` is already false, the second half of the chained expression is ignored altogether (since `False and something_else` returns `False` whatever the value of `something_else` would be).
See the comparisons expressions documentation:
Comparisons can be chained arbitrarily, e.g., `x < y <= z` is equivalent to `x < y and y <= z`, except that `y` is evaluated only once (but in both cases `z` is not evaluated at all when `x < y` is found to be false).
For the record, `<`, `>`, `==`, `>=`, `<=`, `!=`, `is`, `is not`, `in` and `not in` are all comparison operators (as is the deprecated `<>`).
In general, don't compare against booleans; just test the expression itself. If you have to test against a boolean literal, at least use parenthesis and the `is` operator, `True` and `False` are singletons, just like `None`:
>>> (1 in ()) is False
True
This gets more confusing still when integers are involved. The Python `bool` type is a subclass of `int`1. As such, `False == 0` is true, as is `True == 1`. You therefor can conceivably create chained operations that almost look sane:
3 > 1 == True
is true because `3 > 1` and `1 == True` are both true. But the expression:
3 > 2 == True
is false, because `2 == True` is false.
1 `bool` is a subclass of `int` for historic reasons; Python didn't always have a `bool` type and overloaded integers with boolean meaning just like C does. Making `bool` a subclass kept older code working.
Problem
As expected, 1 is not contained by the empty tuple ``` >>> 1 in () False ``` but the `False` value returned is not equal to `False` ``` >>> 1 in () == False False ``` Looking at it another way, the `in` operator returns a `bool` which is neither `True` nor `False`: ``` >>> type(1 in ()) <type 'bool'> >>> 1 in () == True, 1 in () == False (False, False) ``` However, normal behaviour resumes if the original expression is parenthesized ``` >>> (1 in ()) == False True ``` or its value is stored in a variable ``` >>> value = 1 in () >>> value == False True ``` This behaviour is observed in both Python 2 and Python 3. Can you explain what is going on?