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 -- https://mail.python.org/mailman/listinfo/python-list