67

I've noticed that both of these work the same:

if x not in list and if not x in list.

Is there some sort of difference between the two in certain cases? Is there a reason for having both, or is it just because it's more natural for some people to write one or the other?

Which one am I more likely to see in other people's code?

wjandrea
  • 23,210
  • 7
  • 49
  • 68
avacariu
  • 2,584
  • 3
  • 23
  • 25
  • 1
    It's perfectly acceptable to close an older question as a duplicate of a newer one. See http://meta.stackoverflow.com/q/255410, http://meta.stackexchange.com/a/147651 – ThisSuitIsBlackNot Jan 05 '17 at 00:33

5 Answers5

85

The two forms make identical bytecode, as you can clearly verify:

>>> import dis
>>> dis.dis(compile('if x not in d: pass', '', 'exec'))
  1           0 LOAD_NAME                0 (x)
              3 LOAD_NAME                1 (d)
              6 COMPARE_OP               7 (not in)
              9 JUMP_IF_FALSE            4 (to 16)
             12 POP_TOP             
             13 JUMP_FORWARD             1 (to 17)
        >>   16 POP_TOP             
        >>   17 LOAD_CONST               0 (None)
             20 RETURN_VALUE        
>>> dis.dis(compile('if not x in d: pass', '', 'exec'))
  1           0 LOAD_NAME                0 (x)
              3 LOAD_NAME                1 (d)
              6 COMPARE_OP               7 (not in)
              9 JUMP_IF_FALSE            4 (to 16)
             12 POP_TOP             
             13 JUMP_FORWARD             1 (to 17)
        >>   16 POP_TOP             
        >>   17 LOAD_CONST               0 (None)
             20 RETURN_VALUE        

so obviously they're semantically identical.

As a matter of style, PEP 8 does not mention the issue.

Personally, I strongly prefer the if x not in y form -- that makes it immediately clear that not in is a single operator, and "reads like English". if not x in y may mislead some readers into thinking it means if (not x) in y, reads a bit less like English, and has absolutely no compensating advantages.

Alex Martelli
  • 811,175
  • 162
  • 1,198
  • 1,373
  • 6
    PEP 8 mentions a similar preference: “Use `is not` operator rather than `not ... is`. While both expressions are functionally identical, the former is more readable and preferred.” – Walter Tross Jan 12 '19 at 12:58
7
>>> dis.dis(lambda: a not in b)
1           0 LOAD_GLOBAL              0 (a)
          3 LOAD_GLOBAL              1 (b)
          6 COMPARE_OP               7 (not in)
          9 RETURN_VALUE      

>>> dis.dis(lambda: not a in b)
1           0 LOAD_GLOBAL              0 (a)
          3 LOAD_GLOBAL              1 (b)
          6 COMPARE_OP               7 (not in)
          9 RETURN_VALUE  

when you do "not a in b" it will need be converted for (not in)

so, the right way is "a not in b".

killown
  • 4,037
  • 3
  • 23
  • 28
3

not x in L isn't explicitly disallowed because that would be silly. x not in L is explicitly allowed (though it compiles to the same bytecode) because it's more readable.

x not in L is what everyone uses, though.

habnabit
  • 9,330
  • 3
  • 31
  • 26
3

When you write a not in b it is using the not in operator, whereas not a in b uses the in operator and then negates the result. But the not in operator is defined to return the same as not a in b so they do exactly the same thing. From the documentation:

The operators in and not in test for collection membership. x in s evaluates to true if x is a member of the collection s, and false otherwise. x not in s returns the negation of x in s.

Similarly there is a is not b versus not a is b.

The extra syntax was added because it makes it easier for a human to read it naturally.

Mark Byers
  • 767,688
  • 176
  • 1,542
  • 1,434
  • 1
    The strange part is when you use the `dis` module, it shows that they both compare using `not in` despite what the docs say... – avacariu Aug 28 '10 at 19:36
0

It just personal preference. You could also compare if x != 3 and if not x == 3. There's no difference between the two expressions you've shown.

Ned Batchelder
  • 345,440
  • 70
  • 544
  • 649