1

Consider the following sample snippet

import abc


class BASE(metaclass=abc.ABCMeta):
    def __init__(self, name):
        assert name is not None, "Name must be provided."
        self.num = 3

    @abc.abstractmethod
    def compute(self):
        pass


class CHILD(BASE):
    def __init__(name):
         '''
         '''


    def compute(self):
        return self.num + 34

On execution it gives the following sensible error :

AttributeError: 'CHILD' object has no attribute 'num'

In the present situation BASE is not being initialized because if we add a print function to it as below, it does not print absolutely anything.

class BASE(metaclass=abc.ABCMeta):
    def __init__(self, name):
        print(name)
        assert name is not None, "Name must be provided."
        self.num = 3

Can we do anything in this class design to make sure that an implementor subclassing from BASE must explicitly call the initializer of the BASE ?

Ujjwal
  • 1,628
  • 2
  • 10
  • 18
  • Would it suffice to only assure that `self.num` is defined? If so, the `@abstractproperty` decorator can do the trick... or stacking `@abstractmethod` and `@property` (Python 3.3+). More details: https://stackoverflow.com/questions/5960337/how-to-create-abstract-properties-in-python-abstract-classes – plamut Nov 28 '17 at 22:22
  • . umm. In this case yes, it would suffice. But I was thinking about more complicated and larger-scale projects, where for example a parent class might work to initialize some database or do some authentication or do some other non-trivial work. In such a case an enforced explicit initialization would matter (or so I think). – Ujjwal Nov 28 '17 at 22:26
  • I see... and this must happen when an instance of a child class is instantiated? That is, not when the child class itself is created? – plamut Nov 28 '17 at 22:34
  • 1
    I think that if you speculate by design that it is up to the subclass writer to ensure they call super. – kyle Nov 28 '17 at 22:44
  • 2
    +1 on comment by @kyle - in Python it is generally assumed that we are all consenting adults. Which means that if you properly document your base class and how it should be subclassed (including calling its `__init__()` method), it is not unreasonable to assume that an adult person using it will read the docs and honor its expectations. – plamut Nov 28 '17 at 23:02
  • @plamut I used "instantiated" to refer to `__init__` because strictly speaking `__init__` is not a constructor. @kyle Maybe you are right. I am not an expert in design patterns. I just wanted to understand that how in real world problems, designs are made to ensure that such mistakes do not happen. – Ujjwal Nov 28 '17 at 23:02

1 Answers1

0

Can we do anything in this class design to make sure that an implementor subclassing from BASE must explicitly call the initializer of the BASE ?

I guess you can do something like this:

class BASE(metaclass=abc.ABCMeta):
    '''
    when subclassing this class, ensure you explicitly 
    call super().__init__() for this parent class
    '''
    def __init__(self, name):
        assert name is not None, "Name must be provided."
        self.num = 3

From comments secion:

I just wanted to understand that how in real world problems, designs are made to ensure that such mistakes do not happen

I have done many sub-classes where I did not explicitly call the super().__init__() of the parent class. So I am not sure if you can say that all sub-classes must call the parent class __init__ to avoid "mistakes" (as you call it). It is up to the creator of the parent class to document properly how to sub-class, and then it is still up to the creator of the sub-class to either do it or not. Not something you can "enforce"

Edwin van Mierlo
  • 2,398
  • 1
  • 10
  • 19