Why does __ne__ exist?

Chris Angelico rosuav at gmail.com
Sun Jan 7 16:51:08 EST 2018


On Mon, Jan 8, 2018 at 7:41 AM, bartc <bc at freeuk.com> wrote:
> On 07/01/2018 19:55, Chris Angelico wrote:
>
>> Under what circumstances would you want "x != y" to be different from
>> "not (x == y)" ? How would this make for sane behaviour?
>
>
> Presumably so that any behaviour any be programmed when overriding these
> operators.
>
> 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)
>
> Although here, you would probably define 'not' so that 'not (1,1,0)' does
> actually yield '(0,0,1)'.
>
> So clearly I need a weirder example.

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.

>  Even when
>>
>> other things go weird with equality checks, that basic parallel is
>> always maintained:
>>
>>>>> z = float("nan")
>>>>> z == z
>>
>> False
>>>>>
>>>>> z != z
>>
>> True
>>
>> Python gives us a "not in" operator that uses __contains__ and then
>> negates the result. There is no way for "x not in y" to be anything
>> different from "not (x in y)", as evidenced by the peephole optimizer:
>>
>>>>> 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
>>>>>
>>>>> dis.dis("not (x in y)")
>>
>>    1           0 LOAD_NAME                0 (x)
>>                2 LOAD_NAME                1 (y)
>>                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. I did this on CPython 3.7, fwiw, but it
doesn't really matter.

ChrisA



More information about the Python-list mailing list