# Why does __ne__ exist?

```On 07/01/2018 21:51, Chris Angelico wrote:
> On Mon, Jan 8, 2018 at 7:41 AM, bartc <bc at freeuk.com> wrote:

>> Maybe someone wants to do weird stuff with == that doesn't yield a true or
>> false result, so that you can't just reverse it for !=.
>>
>> For example (perhaps this is similar to what was suggested in another post):
>>
>>   (10,20,30) == (10,20,40)   yields  (1,1,0)
>>   (10,20,30) != (10,20,40)   yields  (0,0,1)

> With tuples, I absolutely agree with Python's current behaviour: the
> tuples you give are simply not equal. A tuple doesn't represent a
> vector; it represents a specific collection of values, like the
> coordinates of a point in 2D or 3D space. If you look at the two
> points (1,5) and (3,5), they aren't "half equal". They're different
> points, at different locations. They happen to have the same
> elevation, but that's just a point of curiosity.

My (10,20,30) were meant to represent some user-defined type, not an
ordinary tuple. And someone might intend that == operates on two
instances of that type as thought they were vectors. Or any other kind
of behaviour as I said.

But not necessarily some logical inverse of !=.

>>>>>> dis.dis("not (x in y)")
>>>
>>>     1           0 LOAD_NAME                0 (x)
>>>                 4 COMPARE_OP               7 (not in)
>>
>>
>> I get '4 COMPARE OP    6 (in)' here. So they are distinct ops. 'not in'
>> doesn't just call 'in', then apply 'not'. Not here anyway.
>>
>
> The fact that your Python doesn't optimize it is actually beside the
> point; if _any_ Python interpreter can optimize this down, it must be
> semantically identical.

Actually I didn't see the 'not' on the outside of the brackets. I
thought the two expressions were 'not in' and 'in' and that you might
have transcribed the '7 (not in)' part wrongly.

But this reduction isn't necessarily an optimisation. It might just be a
syntactical transformation from 'not (a in b)' to '(a not in b)'

The disassembly for 'in' and 'not in' suggests that these are two
independent operators, which could indeed have behaviours that are not
complements of each other.

On the other hand, when you /did/ want to evaluate 'in' followed by
'not', then you want:

not (a in b)            # compare using 'not in'

to do the same thing as:

temp = a in b           # compare using 'in'
not temp                # apply unary not

Then there might not be the freedom to have in/not in have independent
behaviours.

--
bartc

```