Python Magic Methods with a Stock Sorting Example
Python magic methods, also known as “dunder” methods (short for “double underscore”), allow us to define how custom objects behave in specific situations. Two of the most commonly used magic methods are __str__
and __lt__
. In this blog, we’ll explore how these methods can be used to sort stock and bond objects, giving them custom behaviors for string representation and comparison.
Magic Methods in Focus:
__str__
: This method is called when you use thestr()
function on an object, or when you print the object. It returns the string representation of an object, which should be human-readable.__lt__
: Short for “less than”, this method defines how two objects should be compared when using the<
operator. It’s essential for sorting objects, as it allows Python to know how to order them based on specific attributes.
Problem Scenario: Sorting Stocks and Bonds
Suppose we have two types of financial instruments: stocks and bonds. Each has attributes that define them. For stocks, the key attribute is price
, while for bonds, it’s the yield_amount
. We want to sort a list of these instruments based on these attributes, but we need a custom behavior for both string representation and comparison.
Implementing the Solution
We’ll create two classes, Stock
and Bond
, each inheriting from a common base class, FinancialInstrument
. We’ll override the __str__
and __lt__
methods in each class.
class FinancialInstrument:
def __init__(self, name):
self.name = name
class Stock(FinancialInstrument):
def __init__(self, name, price):
super().__init__(name)
self.price = price
def __str__(self):
return f"Stock: {self.name}, Price: {self.price}"
def __lt__(self, other):
if isinstance(other, Stock):
return self.price < other.price
return NotImplemented
class Bond(FinancialInstrument):
def __init__(self, name, yield_amount):
super().__init__(name)
self.yield_amount = yield_amount
def __str__(self):
return f"Bond: {self.name}, Yield: {self.yield_amount}"
def __lt__(self, other):
if isinstance(other, Bond):
return self.yield_amount < other.yield_amount
return NotImplemented
How It Works:
The
__str__
method in both theStock
andBond
classes returns a nicely formatted string with the instrument’s name and its key attribute (price for stocks and yield for bonds).The
__lt__
method comparesStock
objects by price andBond
objects by yield. When we try to sort a list of stocks or bonds, Python will use the__lt__
method to determine the order.
Example
Let’s create a list of Stock
and Bond
objects and sort them:
# Create a list of stock and bond objects
stocks = [
Stock("Apple", 150),
Stock("Tesla", 1200),
Stock("Microsoft", 300)
]
bonds = [
Bond("US Treasury", 2.5),
Bond("Corporate Bond", 3.8),
Bond("Municipal Bond", 1.7)
]
# Sort the lists
sorted_stocks = sorted(stocks)
sorted_bonds = sorted(bonds)
# Print the sorted lists
print("Sorted Stocks:")
for stock in sorted_stocks:
print(stock)
print("\nSorted Bonds:")
for bond in sorted_bonds:
print(bond)
Output:
Sorted Stocks:
Stock: Apple, Price: 150
Stock: Microsoft, Price: 300
Stock: Tesla, Price: 1200
Sorted Bonds:
Bond: Municipal Bond, Yield: 1.7
Bond: US Treasury, Yield: 2.5
Bond: Corporate Bond, Yield: 3.8
Breaking Down the Solution:
- The
sorted()
function calls the__lt__
method to compare each pair of objects. For stocks, it compares theprice
attribute, and for bonds, it compares theyield_amount
attribute. - The
__str__
method is called automatically when printing the objects, so we get a nicely formatted output.
Conclusion:
Using magic methods like __str__
and __lt__
allows us to customize the behavior of our Python objects in powerful ways. In this example, we customized the string representation and comparison logic for sorting stocks and bonds. These methods make our objects more intuitive and Pythonic, allowing us to leverage Python’s built-in functions like sorted()
seamlessly.
Official Python Documentation: Data Model (Magic Methods)
This link takes readers to Python’s official documentation, where they can explore more about magic methods and how they can be used to customize class behavior.