Why does "not(True) in [False, True]" return False?
If I do this:
>>> False in [False, True]
True
That returns True . Simply because False is in the list.
But if I do:
>>> not(True) in [False, True]
False
That returns False . Whereas not(True) is equal to False :
>>> not(True)
False
Why?
Operator precedence 2.x, 3.x. The precedence of not is lower than that of in . So it is equivalent to:
>>> not (True in [False, True])
False
This is what you want:
>>> (not True) in [False, True]
True
As @Ben points out: It's recommended to never write not(True) , prefer not True . The former makes it look like a function call, while not is an operator, not a function.
not x in y is evaluated as x not in y
You can see exactly what's happening by disassembling the code. The first case works as you expect:
>>> x = lambda: False in [False, True]
>>> dis.dis(x)
1 0 LOAD_GLOBAL 0 (False)
3 LOAD_GLOBAL 0 (False)
6 LOAD_GLOBAL 1 (True)
9 BUILD_LIST 2
12 COMPARE_OP 6 (in)
15 RETURN_VALUE
The second case, evaluates to True not in [False, True] , which is False clearly:
>>> x = lambda: not(True) in [False, True]
>>> dis.dis(x)
1 0 LOAD_GLOBAL 0 (True)
3 LOAD_GLOBAL 1 (False)
6 LOAD_GLOBAL 0 (True)
9 BUILD_LIST 2
12 COMPARE_OP 7 (not in)
15 RETURN_VALUE
>>>
What you wanted to express instead was (not(True)) in [False, True] , which as expected is True , and you can see why:
>>> x = lambda: (not(True)) in [False, True]
>>> dis.dis(x)
1 0 LOAD_GLOBAL 0 (True)
3 UNARY_NOT
4 LOAD_GLOBAL 1 (False)
7 LOAD_GLOBAL 0 (True)
10 BUILD_LIST 2
13 COMPARE_OP 6 (in)
16 RETURN_VALUE
Operator precedence. in binds more tightly than not , so your expression is equivalent to not((True) in [False, True]) .
