On Sunday, January 7, 2018 at 7:55:57 PM UTC, Chris Angelico wrote: > Whoops, premature send. Picking up from the last paragraph. > > This is good. This is correct. For inequalities, you can't assume that > >= is the exact opposite of < or the combination of < and == (for > example, sets don't behave like numbers, so "x <= y" is very different > from "x < y or x == y"). But the one that confuses me is != or __ne__. > If you don't create it, you get default behaviour: > > >>> class Ham: > ... def __eq__(self, other): > ... print("%s equals %s" % (self, other)) > ... return True > ... > >>> Ham() == 1 > <__main__.Ham object at 0x7fb7557c0278> equals 1 > True > >>> 2 == Ham() > <__main__.Ham object at 0x7fb7557c0278> equals 2 > True > >>> Ham() != 3 > <__main__.Ham object at 0x7fb7557c0278> equals 3 > False > >>> 4 != Ham() > <__main__.Ham object at 0x7fb7557c0278> equals 4 > False > >>> x = Ham() > >>> x == x > <__main__.Ham object at 0x7fb7557b80f0> equals <__main__.Ham object at > 0x7fb7557b80f0> > True > >>> x != x > <__main__.Ham object at 0x7fb7557b80f0> equals <__main__.Ham object at > 0x7fb7557b80f0> > False > > Under what circumstances would you want "x != y" to be different from > "not (x == y)" ? How would this make for sane behaviour? 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) > 6 RETURN_VALUE > > So why isn't != done the same way? Is it historical? > > ChrisA
I'd say this is certainly historical, remembering that in Python 2 you used to be able to compare all sorts of things, whereas in Python 3 you'll get:- >>> 1 < "a" Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: '<' not supported between instances of 'int' and 'str' >>> This seems to be confirmed by the following. From the third paragraph at https://docs.python.org/2/reference/datamodel.html#object.__ne__ "There are no implied relationships among the comparison operators. The truth of x==y does not imply that x!=y is false. Accordingly, when defining __eq__(), one should also define __ne__() so that the operators will behave as expected...". Compare that with the Python 3 equivalent "By default, __ne__() delegates to __eq__() and inverts the result unless it is NotImplemented. There are no other implied relationships among the comparison operators, for example, the truth of (x<y or x==y) does not imply x<=y..." -- Kindest regards. Mark Lawrence. -- https://mail.python.org/mailman/listinfo/python-list