Rich comparison methods are used for comparing object instances. It assigns special methods to each operator as given in below table.

OperatorMethod
==__eq__(self, other)
!=__ne__(self, other)
<__lt__(self, other)
<=__le__(self, other)
>__gt__(self, other)
>=__ge__(self, other)

The correspondence between operator symbols and method names is as follows: x < y calls x.__lt__(y), x>=y calls x.__ge__(y), and so on. These method may return the singleton NotImplemented if it does not implement the operation for a given pair of arguments. For a successful comparison, False and True should be returned. But, these methods can return any value. If the comparison operator is used in a Boolean context (e.g., in the condition of an if statement), Python will call bool() on the value to determine if the result is true or false.

_hash_() Function

It is called by built-in function hash(). It is used for operations on members of hashed collections including set and dict. __hash__() should return an integer. The only required property is that objects which compare equal have the same hash value. Implementation of hashable collections requires that a key’s hash value is immutable (if the object’s hash value changes, it will be in the wrong hash bucket).

If a class does define an __eq__() method it should also define a __hash()__ method. A class that overrides __eq__() and does not define __hash__() will have its __hash__() implicitly set to None. When the __hash__() method of a class is None, instances of the class will raise an appropriate TypeError when a program attempts to retrieve their hash value.

Sorting Class Instance

__lt__() function is used by sorted() to sort list of class instances in particular order. In the below example, employee list is arranged based on their level.

 class Employee():
    def __init__(self, fname, lname, level):
        self.fname = fname
        self.lname = lname
        self.level = level

    # Implement comparison functions

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


def main():

    # Employees list
    employees = []
    employees.append(Employee("Hello", "Baker", 5))
    employees.append(Employee("John", "Doe", 4))
    employees.append(Employee("Jane", "Smith", 6))
    employees.append(Employee("Hitlet", "Durden", 5))

    # Sort the items
    emps = sorted(employees)
    for emp in emps:
        print(emp.lname)

    # Output
    # Doe
    # Baker
    # Durden
    # Smith

if __name__ == "__main__":
    main()

Example

Below example demonstrates the custom implementation of rich comparison operator. Each of these operator uses class attribute for comparing class instance. Employee attribute level is used to find the comparison result.

class Employee():
    def __init__(self, fname, lname, level):
        self.fname = fname
        self.lname = lname
        self.level = level

    # Implement comparison functions
    def __ge__(self, other):
        return self.level >= other.level

    def __gt__(self, other):
        return self.level > other.level

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

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

    def __eq__(self, other):
        return self.level == other.level


def main():

    # Employees list
    employees = []
    employees.append(Employee("Hello", "Baker", 5))
    employees.append(Employee("John", "Doe", 4))
    employees.append(Employee("Jane", "Smith", 6))
    employees.append(Employee("Hitlet", "Durden", 5))

    # Find senior employees
    print(bool(employees[0] < employees[3]))

    # Ouput
    # False

if __name__ == "__main__":
    main()