How to Implement Rich Comparison Ordering in Python Classes
This code demonstrates how to implement rich comparison operators (like <, <=, >, >=, ==, !=) in a Python class by defining __lt__ and __eq__, enabling sorting and ordering of custom objects.
Python code
38 linesclass Task:
def __init__(self, priority, name):
self.priority = priority
self.name = name
def __lt__(self, other):
if not isinstance(other, Task):
return NotImplemented
return self.priority < other.priority
def __eq__(self, other):
if not isinstance(other, Task):
return NotImplemented
return self.priority == other.priority
def __repr__(self):
return f"Task({self.priority}, '{self.name}')"
if __name__ == "__main__":
tasks = [
Task(5, "low"),
Task(1, "critical"),
Task(3, "medium"),
Task(1, "urgent"),
]
tasks.sort()
print("Sorted:", tasks)
a = Task(2, "a")
b = Task(3, "b")
print("a < b:", a < b)
print("a <= b:", a <= b)
print("a > b:", a > b)
print("a >= b:", a >= b)
print("a == b:", a == b)
print("a != b:", a != b)
Output
Sorted: [Task(1, 'critical'), Task(1, 'urgent'), Task(3, 'medium'), Task(5, 'low')]
a < b: True
a <= b: True
a > b: False
a >= b: False
a == b: False
a != b: True
How it works
Python automatically derives the other comparison operators (<=, >, >=) from the __lt__ and __eq__ methods you provide, thanks to the default behavior of the standard library's functools.total_ordering decorator and the default ordering logic in Python 3. By defining __lt__ and __eq__, you give Python enough information to build a complete ordering. The __lt__ method returns NotImplemented when comparing with an incompatible type, which causes Python to fall back to comparing identity or raising a type error rather than guessing. This pattern ensures your custom objects can be sorted, compared, and used in any context that requires an ordered comparison.
Common mistakes
- Only defining `__lt__` and `__eq__` while forgetting that `NotImplemented` should be returned (with capital N) for unsupported types
- Overcomplicating by manually implementing all six comparison methods instead of relying on `__lt__` + `__eq__`
- Defining comparison logic based on a field like `name` when you intend to sort by `priority`
- Forgetting to handle `None` or other incompatible types in comparisons, leading to type errors
Variations
- Use `@functools.total_ordering` decorator explicitly when defining only `__eq__` and`__lt__`, which explicitly documents the decorator-based approach though Python 3 defaults already handle it
- Implement `__gt__` manually when you want different ascending/descending behavior beyond what the default derived comparison provides
Real-world use cases
- Sorting a list of job objects by priority in a queue processing system
- Comparing booking or reservation objects by timestamp to find the earliest available slot
- Ordering database records by a human-readable field such as a product SKU within a reporting script
Sponsored
More from OOP & classes
- Add property getter setter validation in Python easy
- Binary Tree Inorder Traversal in Python easy
- Borg pattern shared state in Python medium
- Bridge Pattern in Python: Separate Abstraction from Implementation medium
- Composable Predicates with the &, |, ~ Operators in Python medium
- Composition over Inheritance: How to Build a Wallet Account in Python easy
Keep learning
Related tutorials and quizzes for this topic.