Why does "not(True) in [False, True]" return False?

31,477

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.

Share:
31,477
Texom512
Author by

Texom512

Updated on January 18, 2021

Comments

  • Texom512
    Texom512 about 3 years

    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?

  • Ben
    Ben almost 9 years
    @Texom512: I would also recommend never writing not(True); prefer not True. The first makes it look like a function call, which is where your confusion came from; if not was a function, then not(True) in ... couldn't possibly be not ((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
    jamylak almost 9 years
    There is always a guy with dis but this is a very valuable answer because it shows that actually not in is used
  • wim
    wim almost 9 years
    Bytecode 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
    Steve Jessop almost 9 years
    Also, 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 write a+b * c+d. So not(True) is bad by that measure too.
  • Alex Pana
    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
    Darkhogg over 8 years
    Actually, never write not True. Write False instead.
  • Nate C-K
    Nate C-K over 8 years
    Presumably in real life you wouldn't be writing not True, you'd be writing something like not myfunc(x,y,z) where myfunc is some function that returns True or False.
  • Ky -
    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 -
    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
    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.