Magic Methods and Operator Overloading
Magic methods, also known as dunder methods (because of the double underscores __), are special methods in Python that allow you to define or modify the behavior of objects. These methods are typically used to implement operator overloading, object representation, and other built-in functions that Python calls on specific objects. This module will explore magic methods, how they work, and how you can use them to customize the behavior of your classes.
Subtopic 1: Introduction to Magic Methods
Magic methods are predefined methods in Python that allow the customization of basic behavior of objects. These methods are automatically called by Python in certain situations, such as during arithmetic operations, object comparisons, or when printing an object.
Magic methods follow a naming convention that uses double underscores (e.g., __init__, __str__), which is why they're often called dunder methods (short for "double underscore").
Example of a Magic Method (Initialization)
class Car:
def __init__(self, make, model):
self.make = make
self.model = model
def __str__(self):
return f'{self.make} {self.model}'
car = Car("Tesla", "Model S")
print(car) # Output: Tesla Model S
In this example, __init__ initializes the object and __str__ defines how the object is represented when printed.
Subtopic 2: Commonly Used Magic Methods (__init__, __str__, __repr__)
-
__init__(self):- The constructor method used for initializing a new object.
- Called automatically when a new instance of the class is created.
Example:
class Car: def __init__(self, make, model): self.make = make self.model = model -
__str__(self):- Defines the string representation of an object, which is used when you print or convert an object to a string.
- Should return a human-readable string.
Example:
class Car: def __init__(self, make, model): self.make = make self.model = model def __str__(self): return f'{self.make} {self.model}' car = Car("Tesla", "Model 3") print(car) # Output: Tesla Model 3 -
__repr__(self):- Defines the official string representation of an object, typically used for debugging.
- Should return a string that, if passed to
eval(), would recreate the object.
Example:
class Car: def __init__(self, make, model): self.make = make self.model = model def __repr__(self): return f"Car(make='{self.make}', model='{self.model}')" car = Car("BMW", "X5") print(repr(car)) # Output: Car(make='BMW', model='X5')__repr__is usually more detailed and meant for development and debugging purposes.
Subtopic 3: Operator Overloading
Operator overloading allows you to define or modify the behavior of operators (like +, -, *, etc.) for user-defined classes. By implementing specific magic methods, you can dictate how objects of your class interact with these operators.
Some commonly used operator overloading magic methods include:
__add__(self, other): Overloads the+operator.__sub__(self, other): Overloads the-operator.__mul__(self, other): Overloads the*operator.__eq__(self, other): Overloads the==operator.__lt__(self, other): Overloads the<operator.
Example of Operator Overloading:
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 __repr__(self):
return f"Point({self.x}, {self.y})"
p1 = Point(1, 2)
p2 = Point(3, 4)
p3 = p1 + p2
print(p3) # Output: Point(4, 6)
In this example, we overloaded the + operator using the __add__ method. When we perform p1 + p2, Python automatically calls the __add__ method to add the two Point objects.
Subtopic 4: Customizing Class Behavior with Magic Methods
By using magic methods, you can change how your class behaves in different contexts. Here are a few examples of how to customize behavior for different operations:
-
__len__(self): Defines the behavior for thelen()function.- Typically used to define the length of a collection (like a list or string).
- Example:
class Book: def __init__(self, title, pages): self.title = title self.pages = pages def __len__(self): return self.pages book = Book("Python Programming", 300) print(len(book)) # Output: 300 -
__getitem__(self, key): Used to define indexing behavior (e.g.,object[key]).- Example:
class Fibonacci: def __init__(self, n): self.sequence = [0, 1] for i in range(2, n): self.sequence.append(self.sequence[-1] + self.sequence[-2]) def __getitem__(self, index): return self.sequence[index] fib = Fibonacci(10) print(fib[4]) # Output: 3 (Fibonacci number at index 4) -
__call__(self, *args, **kwargs): Allows an object to be called like a function.- Example:
class Adder: def __init__(self, start): self.total = start def __call__(self, value): self.total += value return self.total add = Adder(10) print(add(5)) # Output: 15 print(add(10)) # Output: 25
Tasks
-
Task 1: Implementing a
__str__Method- Create a
Bookclass withtitleandauthorattributes. Implement the__str__method to return a string in the format: "Book: <title> by <author>".
- Create a
-
Task 2: Overload the Addition Operator
- Create a
Rectangleclass withlengthandwidthattributes. Overload the+operator to combine two rectangles by adding their corresponding lengths and widths.
- Create a
-
Task 3: Implement a
__repr__Method- Create a
Personclass withnameandageattributes. Implement the__repr__method to return a string like:Person(name='<name>', age=<age>).
- Create a
-
Task 4: Implement the
__len__Method- Create a
Collectionclass with a list of items. Implement the__len__method to return the number of items in the collection.
- Create a
-
Task 5: Operator Overloading
- Create a
Vectorclass that represents a 2D vector withxandycomponents. Overload the*operator to compute the dot product of two vectors.
- Create a
-
Task 6: Callable Objects
- Create a class
Multiplierthat stores afactor. Implement the__call__method to multiply a given number by thefactorwhen the object is called like a function.
- Create a class