Skip to main content

3.5 - Special Methods and Operator Overloading

3.5.1 - Introduction to Special Methods

Special methods in Python, also known as magic or dunder methods, are methods with double underscores at the beginning and end of their names. They allow you to define how objects of your class interact with built-in Python operations.

Example 1: __str__ and __repr__ Methods

class Product:
def __init__(self, name, price):
self.name = name
self.price = price

def __str__(self):
return f"{self.name}: ${self.price}"

def __repr__(self):
return f"Product('{self.name}', {self.price})"

p = Product("Widget", 50)
print(p) # Output using __str__: Widget: $50
print(repr(p)) # Output using __repr__: Product('Widget', 50)

Example 2: __len__ Method

class Inventory:
def __init__(self, items):
self.items = items

def __len__(self):
return len(self.items)

inventory = Inventory(["widget", "gadget"])
print(len(inventory)) # Output: 2

3.5.2 - Operator Overloading

Operator overloading in Python allows you to redefine how built-in operators work with objects of a class. This is achieved by implementing special methods.

Example 1: Overloading Arithmetic Operators

class Point:
def __init__(self, x, y):
self.x = x
self.y = y

def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)

def __sub__(self, other):
return Point(self.x - other.x, self.y - other.y)

p1 = Point(1, 2)
p2 = Point(2, 3)
p3 = p1 + p2
print(p3.x, p3.y) # Output: 3 5

Example 2: Overloading Comparison Operators

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

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

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

book1 = Book("Python 101", 100)
book2 = Book("Python Advanced", 150)
print(book1 == book2) # Output: False
print(book1 > book2) # Output: False

3.5.3 - Practical Use Cases of Special Methods

Understanding the practical use cases of special methods can greatly enhance the usability and integration of your custom classes within the Python ecosystem.

Example: Building a Custom Sequence Type

class MySequence:
def __init__(self, data):
self.data = data

def __getitem__(self, index):
return self.data[index]

def __len__(self):
return len(self.data)

seq = MySequence([1, 2, 3, 4, 5])
print(seq[2]) # Output: 3
print(len(seq)) # Output: 5

3.5.4 - Best Practices and Limitations

While special methods and operator overloading can make your classes more Pythonic and intuitive, it’s important to use them judiciously:

  • Maintain Expected Behavior: Overloaded operators should behave in ways that are consistent with their expected behavior to avoid confusion.

  • Avoid Overcomplicating: Use operator overloading only when it makes the code more readable and maintainable.