Python Comparison and Hash Magic Methods: Practical Code Examples
This article explains Python's comparison and hash magic methods with ten practical code snippets, covering equality, inequality, ordering, hash calculation, total_ordering simplification, custom object sorting, and using objects as dictionary keys, set elements, and memoization caches.
Comparison and hashing are core concepts in Python that affect object equality, ordering, and their use in collections such as dictionaries and sets. The following examples demonstrate how to implement and leverage the related magic methods.
1. 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) # TrueOverriding __eq__ defines how two objects are considered equal.
2. 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) # TrueImplementing __ne__ allows custom inequality behavior.
3. 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 comparisons.
4. Hash value calculation (__hash__)
class Point:
# ...
def __hash__(self):
return hash((self.x, self.y))
p = Point(1, 2)
print(hash(p)) # Example output: 3713081631934410656Overriding __hash__ makes instances usable as dictionary keys or set elements.
5. Simplifying comparisons 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 supplies the remaining ordering methods ( __ne__ , __gt__ , __le__ , __ge__ ) based on __eq__ and __lt__ .
6. Custom object sorting
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. Using 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. Using 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 set elements are unique.
9. Combined use of __eq__, __lt__, and __hash__
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 methods gives full control over equality, ordering, and hash behavior.
10. Memoization with a custom object as 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 as a cache key avoids redundant calculations and speeds up recursive functions.
These ten code snippets illustrate practical applications of Python's comparison and hash magic methods, covering equality, inequality, ordering, hash generation, total_ordering simplification, custom sorting, and using objects as dictionary keys, set elements, and memoization caches.
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.