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?
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
(inverting the value of "x"), it reads a bit less like English, and it has absolutely no compensating advantages.
The if x not in y
form also makes the code much more readable when you have multiple conditions. For example, consider the statement if not x in y and x in m
. A casual reader might think it means if not (x in y and x in m)
, but would get a surprise since the code actually executes as if (not x in y) and (x in m)
. So by moving the not
next to the in
operator it belongs to, you therefore make it clear that the not in
only applies to that particular condition, rather than all of them.
Therefore, if x not in y and x in m
has multiple readability benefits and is easier to understand regardless of programming experience. Furthermore, not in
is the official name of the "not in" bytecode operator (as seen in the disassembly above), regardless of how the user writes it, which further confirms that not in
is Python's preferred style.
Let's also consider a similar statement. The is not
condition. If you attempt to write if not x is True
, it becomes really obvious how silly and backwards that pattern is. Neither of them make any sense logically, but it becomes extra obvious in that is not
example.
In short, if X is not Y
and if X not in Y
are the preferred ways of writing these kinds of Python statements.