python total_ordering : why __lt__ and __eq__ instead of __le__?

comparison-operators, python, python-3.x

Solution

The documentation states you must define one of `__lt__()`, `__le__()`, `__gt__()`, or `__ge__()`, but only should supply an `__eq__()` method.

In other words, the `__eq__` method is optional.

The `total_ordering` implementation does not require you to specify an `__eq__` method; it only tests for the `__lt__()`, `__le__()`, `__gt__()`, or `__ge__()` methods. It supplies up to 3 missing special methods based of one of those 4.

You can't base the order on just `__le__` or `__ge__` because you can't assume that you can swap `a` and `b`; if `b` is a different type `b.__le__` might not be implemented and so your `a < b <=> not (b <= a)` map can't be guaranteed. The implementation uses `(a <= b) and (a != b)` if `__le__` is not defined but `__lt__` has been.

The full table of mappings is:

comparison available alternative

`a > b` `a < b` `(not a < b) and (a != b)`

`a <= b` `(not a <= b)`

`a >= b` `(a >= b) and (a != b)`

`a <= b` `a < b` `(a < b) or (a == b)`

`a > b` `(not a > b)`

`a >= b` `(not a >= b) or (a == b)`

`a < b` `a <= b` `(a <= b) and (a != b)`

`a > b` `(not a > b) and (a != b)`

`a >= b` `(not a >= b)`

`a >= b` `a < b` `(not a < b)`

`a <= b` `(not a <= b) or (a == b)`

`a > b` `(a > b) or (a == b)`

The `__eq__` method is optional because the base `object` object defines one for you; two instances are considered equal only if they are the same object; `ob1 == ob2` only if `ob1 is ob2` is `True`. See the `do_richcompare()` function in `object.c`; remember that the `==` operator in the code there is comparing pointers.

Problem

In Python3, the functools.total_ordering decorator allows one to only overload `__lt__` and `__eq__` to get all 6 comparison operators. I don't get why one has to write two operators when one would be enough, namely `__le__` or `__ge__`, and all others would be defined accordingly : ``` a < b <=> not (b <= a) a > b <=> not (a <= b) a == b <=> (a <= b) and (b <= a) a != b <=> (a <= b) xor (b <= a) ``` Is that just because xor operator does not exists natively?

Original source