Why does "not(True) in [False, True]" return False?
Solution 1
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.
Solution 2
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
Solution 3
Operator precedence. in
binds more tightly than not
, so your expression is equivalent to not((True) in [False, True])
.
Solution 4
It's all about operator precedence (in
is stronger than not
). But it can be easily corrected by adding parentheses at the right place:
(not(True)) in [False, True] # prints true
writing:
not(True) in [False, True]
is the same like:
not((True) in [False, True])
which looks if True
is in the list and returns the "not" of the result.
Solution 5
It is evaluating as not True in [False, True]
, which returns False
because True
is in [False, True]
If you try
>>>(not(True)) in [False, True]
True
You get the expected result.
Texom512
Updated on January 18, 2021Comments
-
Texom512 about 3 years
If I do this:
>>> False in [False, True] True
That returns
True
. Simply becauseFalse
is in the list.But if I do:
>>> not(True) in [False, True] False
That returns
False
. Whereasnot(True)
is equal toFalse
:>>> not(True) False
Why?
-
Ben almost 9 years@Texom512: I would also recommend never writing
not(True)
; prefernot True
. The first makes it look like a function call, which is where your confusion came from; ifnot
was a function, thennot(True) in ...
couldn't possibly benot ((True) in ...)
. You have to know it's an operator (or you end up in situations like this), so you should write it like an operator, not disguise it as a function. -
jamylak almost 9 yearsThere is always a guy with
dis
but this is a very valuable answer because it shows that actuallynot in
is used -
wim almost 9 yearsBytecode is an implementation detail of the CPython interpreter. This is a CPython answer to a Python question, in fact it can be better answered from the language reference directly.
-
Steve Jessop almost 9 yearsAlso, if you're going to use spacing to indicate precedence for the benefit of the reader, first make sure you're right. It's probably OK to write
a + b*c + d
, it's very bad to writea+b * c+d
. Sonot(True)
is bad by that measure too. -
Alex Pana almost 9 years@wim I would argue that the bytecode implementation is not as important as the actual disassembly. Other implementations are guaranteed to generate something functionally identical, so understanding one disassembly offers enough insight to understand the "why" and not the lowlevel "how".
-
Darkhogg over 8 yearsActually, never write
not True
. WriteFalse
instead. -
Nate C-K over 8 yearsPresumably in real life you wouldn't be writing
not True
, you'd be writing something likenot myfunc(x,y,z)
wheremyfunc
is some function that returnsTrue
orFalse
. -
Ky - over 8 years@YuHao I would enjoy your explanation as to why you reversed my edits, as I believe they help readers better understand what's going on.
-
Ky - over 8 years@YuHao yes, the parentheses in
(True)
are redundant. However, they were in the original question, so taking them out actually makes it more confusing, since it's harder to tell how your answer relates to the OP's question. Additionally, they weren't in your recommended fix ("This is what you want:"), so I wasn't intending them to be something anyone SHOULD do, just a visual aid to relate it to the problem code. -
Yu Hao over 8 years@BenC.R.Leggiero That's what I did in the original answer, and others have corrected it. The current version is clear enough for me, I don't think it's hard to understand without the redundant parentheses, since the key problem has been pointed out, understanding the rest is a programmer's basic skill.