Python Classes with Comparison Magic Methods

In Python, custom objects don’t know how to compare themselves with other objects out-of-the-box. By default, two different instances of a class will be considered unequal unless explicitly instructed otherwise. However, Python offers a way to define custom comparison behavior using magic methods.

In this blog post, we’ll explore how to implement comparison methods in a custom class. We’ll use a Book class as an example to illustrate this concept.

Understanding Magic Methods

Magic methods in Python, also known as dunder methods (due to the double underscores), allow you to define how operators behave with your custom objects. Specifically, methods like __eq__, __lt__, and __gt__ enable comparison operations such as equality, less than, and greater than.

Implementing the Book Class

Let’s create a Book class that supports comparisons based on book attributes like title, author, and price.

Here’s how you can implement this:

				
					class Book:
    def __init__(self, title, author, price):
        self.title = title
        self.author = author
        self.price = price

    def __eq__(self, other):
        if not isinstance(other, Book):
            raise ValueError("Can't compare Book to a non-Book")
        return (self.title == other.title and
                self.author == other.author and
                self.price == other.price)

    def __lt__(self, other):
        if not isinstance(other, Book):
            raise ValueError("Can't compare Book to a non-Book")
        return self.price < other.price

    def __le__(self, other):
        if not isinstance(other, Book):
            raise ValueError("Can't compare Book to a non-Book")
        return self.price <= other.price

    def __gt__(self, other):
        if not isinstance(other, Book):
            raise ValueError("Can't compare Book to a non-Book")
        return self.price > other.price

    def __ge__(self, other):
        if not isinstance(other, Book):
            raise ValueError("Can't compare Book to a non-Book")
        return self.price >= other.price

				
			

Testing the Comparison Methods

Let’s test the comparison methods with some book instances:

				
					# Creating book instances
b1 = Book("To Kill a Mockingbird", "Harper Lee", 24.95)
b2 = Book("The Catcher in the Rye", "J.D. Salinger", 29.95)
b3 = Book("War and Peace", "Leo Tolstoy", 39.95)

# Testing equality
print(b1 == b2)  # False
print(b1 == Book("To Kill a Mockingbird", "Harper Lee", 24.95))  # True

# Testing comparisons
print(b1 < b2)   # True
print(b2 > b1)   # True
print(b1 <= b2)  # True
print(b2 >= b3)  # False

# Sorting a list of books
books = [b1, b2, b3]
books.sort()
print([book.title for book in books])  # Sorted list based on price

				
			

Explanation

  1. Equality (__eq__): This method compares if two books are equal by checking their title, author, and price. It raises an exception if compared with a non-Book object.

  2. Less Than (__lt__): Compares books based on their price to determine if one book is cheaper than another.

  3. Less Than or Equal To (__le__): Checks if a book is cheaper than or equal to another book.

  4. Greater Than (__gt__): Determines if a book is more expensive than another.

  5. Greater Than or Equal To (__ge__): Checks if a book is more expensive than or equal to another.

By implementing these methods, we not only gain the ability to compare books but also to sort them based on their prices using Python’s built-in sort functionality.

Conclusion

Defining comparison magic methods in your classes allows you to leverage Python’s powerful operator overloading capabilities. Whether you are comparing attributes or sorting lists, magic methods provide a flexible and intuitive way to extend the functionality of your custom objects.

For a comprehensive list of magic methods and their usages, refer to the Python Data Model documentation.