2

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?

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
mfvas
  • 115
  • 1
  • 11
  • 1
    Have you tried instantiating ``BaseBacktestPortfolio``? It already is an ABC via inheritance, which should prevent instantiating. – MisterMiyagi Jun 15 '18 at 11:09

2 Answers2

1

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 from the BacktestPortfolio class.

That is the case in your example already:

>>> BaseBacktestPortfolio.mro()
[__main__.BaseBacktestPortfolio, __main__.Portfolio, abc.ABC, object]
>>> BaseBacktestPortfolio()
TypeError: Can't instantiate abstract class BaseBacktestPortfolio with abstract methods check_signal

Since ABC and ABCMeta are just regular types, their features are inherited. This includes their guards against instantiating incomplete classes. Your BaseBacktestPortfolio already is an abstract class.

The warning from your IDE/linter/... exists specifically to warn you that instantiating BaseBacktestPortfolio is not possible.

MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119
0

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 :)

Rahul Goswami
  • 535
  • 3
  • 14
  • 1
    ``BaseBacktestPortfolio`` already is an ``ABC`` by virtue of inheriting from ``Portfolio``. Adding ``ABC`` as an explicit base does not change the mro at all. – MisterMiyagi Jun 22 '18 at 10:46
  • @MisterMiyagi Yeah, I guess you are right. I haven't tried this code without explicitly specifying it as `ABC`. But I have a doubt. By this logic, aren't _all_ the child classes of `ABC` are abstract. We don't want this in most of the cases. – Rahul Goswami Jun 22 '18 at 14:28
  • 1
    Yes, any ABC subclass is abstract unless it implements the entire interface. This is often desirable when defining interfaces. For example, the ``MutableSet`` inherits from ``Set`` but defines the abstract methods ``add`` and ``discard`` in addition. – MisterMiyagi Jun 23 '18 at 16:57