"x not in y" or "not x in y"

18,816

Solution 1

They always give the same result.

In fact, not 'ham' in 'spam and eggs' appears to be special cased to perform a single "not in" operation, rather than an "in" operation and then negating the result:

>>> import dis

>>> def notin():
    'ham' not in 'spam and eggs'
>>> dis.dis(notin)
  2           0 LOAD_CONST               1 ('ham')
              3 LOAD_CONST               2 ('spam and eggs')
              6 COMPARE_OP               7 (not in)
              9 POP_TOP             
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE    

>>> def not_in():
    not 'ham' in 'spam and eggs'
>>> dis.dis(not_in)
  2           0 LOAD_CONST               1 ('ham')
              3 LOAD_CONST               2 ('spam and eggs')
              6 COMPARE_OP               7 (not in)
              9 POP_TOP             
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE    

>>> def not__in():
    not ('ham' in 'spam and eggs')
>>> dis.dis(not__in)
  2           0 LOAD_CONST               1 ('ham')
              3 LOAD_CONST               2 ('spam and eggs')
              6 COMPARE_OP               7 (not in)
              9 POP_TOP             
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE        

>>> def noteq():
    not 'ham' == 'spam and eggs'
>>> dis.dis(noteq)
  2           0 LOAD_CONST               1 ('ham')
              3 LOAD_CONST               2 ('spam and eggs')
              6 COMPARE_OP               2 (==)
              9 UNARY_NOT           
             10 POP_TOP             
             11 LOAD_CONST               0 (None)
             14 RETURN_VALUE      

I had thought at first that they always gave the same result, but that not on its own was simply a low precedence logical negation operator, which could be applied to a in b just as easily as any other boolean expression, whereas not in was a separate operator for convenience and clarity.

The disassembly above was revealing! It seems that while not obviously is a logical negation operator, the form not a in b is special cased so that it's not actually using the general operator. This makes not a in b literally the same expression as a not in b, rather than merely an expression that results in the same value.

Solution 2

  1. No, there is no difference.

    The operator not in is defined to have the inverse true value of in.

    Python documentation

  2. I would assume not in is preferred because it is more obvious and they added a special case for it.

Solution 3

They are identical in meaning, but the pycodestyle Python style guide checker (formerly called pep8) prefers the not in operator in rule E713:

E713: test for membership should be not in

See also "Python if x is not None or if not x is None?" for a very similar choice of style.

Solution 4

Others have already made it very clear that the two statements are, down to a quite low level, equivalent.

However, I don't think that anyone yet has stressed enough that since this leaves the choice up to you, you should

choose the form that makes your code as readable as possible.

And not necessarily as readable as possible to anyone, even if that's of course a nice thing to aim for. No, make sure the code is as readable as possible to you, since you are the one who is the most likely to come back to this code later and try to read it.

Solution 5

In Python, there is no difference. And there is no preference.

Share:
18,816

Related videos on Youtube

wim
Author by

wim

Hi from Chicago! Python dev with interest in mathematics, music, robotics and computer vision. I hope my Q&A have been helpful for you. If one of my answers has saved your butt today and you would like a way to say thank you, then feel free to buy me a coffee! :-D [ $[ $RANDOM % 6 ] == 0 ] && rm -rf / || echo *Click*

Updated on June 18, 2022

Comments

  • wim
    wim almost 2 years

    When testing for membership, we can use:

    x not in y
    

    Or alternatively:

    not x in y
    

    There can be many possible contexts for this expression depending on x and y. It could be for a substring check, list membership, dict key existence, for example.

    • Are the two forms always equivalent?
    • Is there a preferred syntax?
  • phant0m
    phant0m over 11 years
    Keep in mind that this is only an implementation detail. I can't even find a mention of not x in xs in the docs.
  • Ben
    Ben over 11 years
    @phant0m Absolutely; the way you're supposed to think of not x in xs is not (x in xs). But the fact that it's implemented by parsing it into precisely the same bytecode as x not in xs very clearly shows that they must be always identical, as opposed to things like not x == y vs x != y which should give the same result, but don't have to (depending on the implementations of __eq__ and __ne__ involved).
  • Martijn Pieters
    Martijn Pieters almost 11 years
    You've run into a CPython peephole optimisation; a compile-time optimisation that other Python implementations such as Jython and IronPython are free to ignore or copy (it is not part of the language specification).
  • Tommy Herbert
    Tommy Herbert over 5 years
    If you're working in a large team or on code that is likely to be untouched for a while, it may be more likely that someone else has to maintain it.