Solution Overview Stocks and Bonds

In a previous challenge, we explored how to represent financial assets like stocks and bonds using inheritance in Python. This blog post reviews a solution to that challenge, where we created a class structure that leverages inheritance to group common properties while ensuring that subclasses implement specific behaviors. Let’s dive into the solution and see how it addresses the requirements.

Problem Recap

The challenge was to create a class structure with the following requirements:

  1. Base Class: A common base class (Asset) should be created to hold shared attributes such as price.
  2. Stock Class: A subclass (Stock) should represent a stock, including attributes like company_name and ticker_symbol.
  3. Bond Class: Another subclass (Bond) should represent a bond, including attributes like description, duration, and yield_percentage.
  4. Abstract Base Class: The base class should be abstract, meaning it cannot be instantiated directly, and it should enforce that subclasses override the get_description method.
  5. Specific Implementations: Each subclass should implement the get_description method to return a string that provides information specific to that asset type.

Step-by-Step Solution

Let’s break down the solution into key components.

1. Creating the Abstract Base Class

The first step was to define an abstract base class Asset. This class includes the price attribute and an abstract method get_description, which must be implemented by any subclass.

				
					from abc import ABC, abstractmethod

class Asset(ABC):
    def __init__(self, price):
        self.price = price
    
    @abstractmethod
    def get_description(self):
        pass

				
			

By using the ABC (Abstract Base Class) module, we ensure that Asset cannot be instantiated directly. The @abstractmethod decorator is used to enforce that any subclass of Asset must implement the get_description method.

2. Implementing the Stock Class

Next, the Stock class was created as a subclass of Asset. This class introduces additional attributes, company_name and ticker_symbol, and provides its own implementation of get_description.

				
					class Stock(Asset):
    def __init__(self, price, company_name, ticker_symbol):
        super().__init__(price)
        self.company_name = company_name
        self.ticker_symbol = ticker_symbol
    
    def get_description(self):
        return f"Stock: {self.company_name} ({self.ticker_symbol}), Price: ${self.price:.2f}"

				
			

The get_description method in the Stock class returns a formatted string that includes details about the stock.

3. Implementing the Bond Class

Similarly, the Bond class was created as a subclass of Asset. It introduces description, duration, and yield_percentage as additional attributes, and provides its own implementation of get_description.

				
					class Bond(Asset):
    def __init__(self, price, description, duration, yield_percentage):
        super().__init__(price)
        self.description = description
        self.duration = duration
        self.yield_percentage = yield_percentage
    
    def get_description(self):
        return (f"Bond: {self.description}, Duration: {self.duration} years, "
                f"Yield: {self.yield_percentage:.2f}%, Price: ${self.price:.2f}")

				
			

The get_description method in the Bond class returns a formatted string that includes details about the bond.

Testing the Solution

To test the solution, we can create instances of Stock and Bond and then call the get_description method on each. Attempting to instantiate the Asset class directly should result in an error.

				
					if __name__ == "__main__":
    try:
        # This should raise an error because Asset is abstract
        asset = Asset(1000)
    except TypeError as e:
        print(f"Error: {e}")
    
    # Create a Stock instance
    apple_stock = Stock(150.00, "Apple Inc.", "AAPL")
    print(apple_stock.get_description())

    # Create a Bond instance
    treasury_bond = Bond(1000.00, "U.S. Treasury Bond", 10, 1.5)
    print(treasury_bond.get_description())

				
			

Running the code above produces the following output:

				
					Error: Can't instantiate abstract class Asset with abstract method get_description
Stock: Apple Inc. (AAPL), Price: $150.00
Bond: U.S. Treasury Bond, Duration: 10 years, Yield: 1.50%, Price: $1000.00

				
			

As expected, attempting to instantiate Asset directly results in a TypeError, while the Stock and Bond instances provide specific descriptions based on their respective attributes.