Search code examples
pythonpython-3.xabstract-class

Proper way to implement ABC SubClass


I have an Interface class which defines the requirements to an active "in-use" class:

class Portfolio(ABC):
    @abstractmethod
    def update_portfolio(self):
        raise NotImplementedError

    @abstractmethod
    def update_from_fill(self):
        raise NotImplementedError

    @abstractmethod
    def check_signal(self, signal_event):
        raise NotImplementedError

The methods update_portfolio and update_from_fill are both methods which will be the same in 99% of the required cases. Only the check_signal method will vary. Therefore, to avoid having to write the same code again and again, I have defined a base class with default methods for update_portfolio and update_from_fill:

class BaseBacktestPortfolio(Portfolio):
    def __init__(self, ...):
        ...

    def update_portfolio(self, ...):
        ...

    def update_from_fill(self, ...):
        ...

Then, finally, I have a class inheriting from the BacktestPortfolio class which specifies the correct implementation of the check_signal method:

class USBacktestPortfolio(BaseBacktestPortfolio):
    def check_signal(self, ...):
        ...

Now, the problem is that my editor complains about the BacktestPortfolio classing not having all the required abstract methods. I could ignore this, of course, but the perfect scenario would be if I could make sure that it is not possible to instantiate an object form the BacktestPortfolio class.

Is this possible? And/or is there a more correct way to implement a structure like this?


Solution

  • You can make the BaseBacktestPortfolio also as Abstract class.

    from abc import ABC, abstractmethod
    
    class Portfolio(ABC):
        @abstractmethod
        def update_portfolio(self):
            pass
    
        @abstractmethod
        def update_from_fill(self):
            pass
    
        @abstractmethod
        def check_signal(self, signal_event):
            pass
    
    class BaseBacktestPortfolio(Portfolio, ABC):
    
        def update_portfolio(self):
            print("updated portfolio")
    
        def update_from_fill(self):
            print("update from fill")
    
        @abstractmethod
        def check_signal(self):
            pass
    
    class USBacktestPortfolio(BaseBacktestPortfolio):
        def check_signal(self):
            print("checked signal")
    

    Also notice that you don't need raise NotImplementedError inside abstract method. You can just pass. Its more Pythonic :)