"X Not in Y" or "Not X in Y"

x not in y or not x in y

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.

x not in vs. not x in

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.

Does `not x in y` follow the operator precedence rules?

Rather subtle but if you look in the official documentation that you linked to, you will see that "not in" is its own operator, which has a higher precedence than "not" and the same precedence as "in".

Your mistake is probably coming from reading the operator precedence rules the wrong way around. As it currently stands, the lowest precedence comes higher up in the list.
So not x in list2 is equvalent to not (x in list2).

Your last assumption will, because you have surrounded it with parentheses, first evaluate not x to a boolean (False), then check if that boolean is in the list (which it is not, there's only a string in the list), and return False.

python if (X not in Y) or (Z not in Y) condition unexpected result

Try this code :

files = ["f1", "f2", "f3", "f4", "f1.txt", "f3.pdf"]
for f in files:
if f+".txt" not in files and f+".pdf" not in files:
print(f)

Which is faster? if not x in OR if x not in

They are exactly the same, and thus take the same amount of time. not in is just syntactic sugar. Using the dis module, we can see that both result in the same bytecode:

>>> dis.dis("not x in y")
1 0 LOAD_NAME 0 (x)
2 LOAD_NAME 1 (y)
4 COMPARE_OP 7 (not in)
6 RETURN_VALUE
>>> dis.dis("x not in y")
1 0 LOAD_NAME 0 (x)
2 LOAD_NAME 1 (y)
4 COMPARE_OP 7 (not in)
6 RETURN_VALUE

Even adding parentheses as not (x in y) does not change that, unless, of course, you add more to the parentheses:

>>> dis.dis("not (x in y)")
1 0 LOAD_NAME 0 (x)
2 LOAD_NAME 1 (y)
4 COMPARE_OP 7 (not in)
6 RETURN_VALUE
>>> dis.dis("not (x in y or z)")
1 0 LOAD_NAME 0 (x)
2 LOAD_NAME 1 (y)
4 COMPARE_OP 6 (in)
6 JUMP_IF_TRUE_OR_POP 10
8 LOAD_NAME 2 (z)
>> 10 UNARY_NOT
12 RETURN_VALUE

Tested with both, Python 3.6.7 and 2.7.15.

Python `if x is not None` or `if not x is None`?

There's no performance difference, as they compile to the same bytecode:

>>> import dis
>>> dis.dis("not x is None")
1 0 LOAD_NAME 0 (x)
2 LOAD_CONST 0 (None)
4 COMPARE_OP 9 (is not)
6 RETURN_VALUE
>>> dis.dis("x is not None")
1 0 LOAD_NAME 0 (x)
2 LOAD_CONST 0 (None)
4 COMPARE_OP 9 (is not)
6 RETURN_VALUE

Stylistically, I try to avoid not x is y, a human reader might misunderstand it as (not x) is y. If I write x is not y then there is no ambiguity.

Pythonic way to write for x in Y and not in Z

The List Comprehension would look like this

>>> [item for item in Arr1 if item not in Arr2]
[-1, 0]

But, this is highly inefficient, as it has to do M * N iterations in the worst case, because the in operator will have to iterate through the elements of Arr2 sequentially. So, better convert the Arr2 to a set and then do it in the same way

>>> set2 = set(Arr2)
>>> [item for item in Arr1 if item not in set2]
[-1, 0]

Since we use a set here, which uses hashing to do the lookup, it would be faster than the linear list search approach.

If you have the liberty of converting both the lists to sets, and the order of the elements in the result doesn't matter, simply convert both the lists to sets and find the set difference, like this

>>> set1, set2 = set(Arr1), set(Arr2)
>>> set1 - set2
set([0, -1])

Just to show the impact of linear list searching in this list comprehension, just check this timing comparison.

>>> import random
>>> import timeit
>>>
>>> def get_random_numbers(count=100):
>>> return [random.randint(0, 10000) for _ in range(count)]
>>>
>>> data1, data2 = get_random_numbers(10000), get_random_numbers(10000)
>>> set1, set2 = set(data1), set(data2)
>>>
>>> timeit.timeit("[item for item in data1 if item not in data2]",
setup="from __main__ import data1, data2", number=100)
>>> 47.4242498875
>>> timeit.timeit("[item for item in data1 if item not in set2]",
setup="from __main__ import data1, set2", number=100)
>>> 0.0595960617065
>>> timeit.timeit("list(set1 - set2)",
setup="from __main__ import set1, set2", number=100)
>>> 0.033539056778

All the results are in seconds. See the magnitude of performance boost you get by using sets.

In python, in what order would x = y == true evaluate

It is more obvious if you add parentheses according to operator precedence:

x = (y == "true")

y == "true" is an expression that evalutates to a bool, so it will be True or False. That value is then assigned to x.

Or in more words:

if y == "true":
x = True
else:
x = False

Is there a difference between != and is not in C#?

Comparison table:













































































Operator!=is not
Original purposeValue inequalityNegated pattern matching
Can perform value inequalityYesYes
Can perform negated pattern matchingNoYes
Can invoke implicit operator on left-hand operandYesNo
Can invoke implicit operator on right-hand operand(s)YesYes1
Is its own operatorYesNo2
OverloadableYesNo
SinceC# 1.0C# 9.03
Value-type null-comparison branch elision4YesNo[Citation needed]5
Impossible comparisonsErrorWarning
Left operandAny expressionAny expression
Right operand(s)Any expressionOnly constant expressions6
Syntax<any-expr> != <any-expr><any-expr> is [not] <const-expr> [or|and <const-expr>]*
and more



Related Topics



Leave a reply



Submit