Practical Python Comparison and Hashing Magic Methods – 10 Code Examples
This article presents ten practical Python code examples demonstrating how to implement and use comparison and hashing magic methods such as __eq__, __ne__, __lt__, __hash__, and related utilities like functools.total_ordering and memoization for custom objects.
Comparison and hashing are essential concepts in Python, influencing object equality, ordering, and their use in collections. The following ten examples illustrate common scenarios where magic methods are overridden to customize these behaviors.
1. Implement equality comparison (__eq__)
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
if isinstance(other, Point):
return self.x == other.x and self.y == other.y
return False
p1 = Point(1, 2)
p2 = Point(1, 2)
print(p1 == p2) # TrueBy overriding __eq__ , objects can define their own equality logic.
2. Implement inequality comparison (__ne__)
class Point:
# ...
def __ne__(self, other):
return not self.__eq__(other)
p1 = Point(1, 2)
p2 = Point(3, 4)
print(p1 != p2) # TrueOverriding __ne__ allows custom inequality behavior.
3. Implement less‑than comparison (__lt__)
class Point:
# ...
def __lt__(self, other):
if isinstance(other, Point):
return self.x < other.x and self.y < other.y
return NotImplemented
p1 = Point(1, 2)
p2 = Point(3, 4)
print(p1 < p2) # TrueDefining __lt__ enables ordering of custom objects.
4. Implement hash value calculation (__hash__)
class Point:
# ...
def __hash__(self):
return hash((self.x, self.y))
p = Point(1, 2)
print(hash(p)) # e.g., 3713081631934410656Overriding __hash__ makes instances usable as dictionary keys or set elements.
5. Simplify comparison methods with functools.total_ordering
from functools import total_ordering
@total_ordering
class Point:
# ...
def __eq__(self, other):
# ...
def __lt__(self, other):
# ...The total_ordering decorator automatically generates the remaining rich comparison methods.
6. Custom object sorting by defining __lt__
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __lt__(self, other):
if isinstance(other, Person):
return self.age < other.age
return NotImplemented
people = [Person("Alice", 25), Person("Bob", 30), Person("Charlie", 20)]
sorted_people = sorted(people)
for person in sorted_people:
print(person.name, person.age)Implementing __lt__ lets sorted() order custom objects.
7. Use custom objects as dictionary keys
class Point:
# ...
def __hash__(self):
return hash((self.x, self.y))
p1 = Point(1, 2)
p2 = Point(3, 4)
data = {p1: "value1", p2: "value2"}
print(data[p1]) # value1Defining __hash__ (and __eq__ ) enables objects to serve as dictionary keys.
8. Use custom objects as set elements
class Point:
# ...
def __eq__(self, other):
# ...
def __hash__(self):
return hash((self.x, self.y))
p1 = Point(1, 2)
p2 = Point(3, 4)
my_set = {p1, p2}
print(len(my_set)) # 2Providing both __eq__ and __hash__ ensures proper set behavior.
9. Combine __eq__, __lt__, and __hash__ for full comparison and hashing
class Point:
# ...
def __eq__(self, other):
# ...
def __lt__(self, other):
# ...
def __hash__(self):
return hash((self.x, self.y))
p1 = Point(1, 2)
p2 = Point(3, 4)
p3 = Point(1, 2)
print(p1 == p2) # False
print(p1 < p2) # True
my_set = {p1, p2, p3}
print(len(my_set)) # 2Combining these magic methods gives complete control over equality, ordering, and hashability.
10. Memoization using a custom callable object as a cache key
class Memoize:
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args):
if args in self.cache:
return self.cache[args]
result = self.func(*args)
self.cache[args] = result
return result
@Memoize
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) # 55Using a custom object with __call__ and a hashable argument tuple provides an efficient memoization pattern.
These ten scenarios demonstrate how Python’s magic methods for comparison and hashing can be applied to define object equality, ordering, hashability, simplify implementations with functools.total_ordering , and create performant caching mechanisms.
Test Development Learning Exchange
Test Development Learning Exchange
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.