Search code examples
pythonclassmagic-methods

Class comparisons (like __ge__) without functools total_ordering


The following code works, but surprisingly also for the methods that have not been implemented. Normally you need total_ordering to accomplish this, right?

class Account:

    def __init__(self, balance=0):
        self.balance = balance

    def __lt__(self, other):
        return self.balance < other.balance

    def __le__(self, other):
        return self.balance <= other.balance


acc1 = Account(100)
acc2 = Account(200)

print(acc1 < acc2)   # True
print(acc1 >= acc2)  # False, but __ge__ is not defined
print(acc1 == acc2)  # False, but __eq__ is not defined

Is it safe to do this without total_ordering or will this lead to surprises?


Solution

  • Two things are happening here.

    The first is that == is always defined by default, inherited from object.__eq__. Essentially it, works by identity, which is not what you expect here.

    The second is described in the documentation:

    There are no swapped-argument versions of these methods (to be used when the left argument does not support the operation but the right argument does); rather, __lt__() and __gt__() are each other’s reflection, __le__() and __ge__() are each other’s reflection, and __eq__() and __ne__() are their own reflection.

    So, this is like __add__ and __radd__. In the case of acc1 >= acc2, the left operand does not support __gt__, so this is delegated to the right operand's __le__.