KubiK888
KubiK888

Reputation: 4723

How to use parent class to enforce subclasses to set value to an attribute?

I want the Parent class to have a checking mechanism to ensure all its subclasses to set an actual value to the attribute name. I found something here.

class Parent(object):
    #name = None
    def __init__(self):
        if self.name == None:
            raise NotImplementedError('Subclasses must define name')

class Child1(Parent):
    pass

class Child2(Parent):
    name = 'test'

class Child3(Parent):
    def __init__(self):
        self.name = 'test'

class Child4(Parent):
    def __init__(self):
        pass

#obj1 = Child1() # Expected output: NotImplementedError: Subclasses must define bar

obj2 = Child2()

obj3 = Child3()

obj4 = Child4() # I want the NotImplementedError is raised here as well, but it doesn't

The problem is as long as there is an __init__ method in the subclass, it overwrites the Parent class and the raise NotImplementedError is no longer in effect.

My current working solution is:

class Child5(Parent):
    def __init__(self):
        self.name = 'test'
        super().__init__()

obj5 = Child5() 

which seems to work, but I wonder if it's a proper implementation, or if it may have some hidden pitfalls, and also if I should learn to use/implement @abstractproperty instead of this solution?

Upvotes: 0

Views: 469

Answers (1)

Prajyot Naik
Prajyot Naik

Reputation: 86

Here, you need to understand when you parent class constructor gets called. Note that while creating child class objects, if child class has a constructor it is called by default. It is up to us whether we want to call parent class constructor as well and this shall be done by us. However if child class doesn't have a constructor, then the base class constructor is called.

So with your Child1(), parent constructor is called by default so it raises the exception.

In your Child2() as well parent constructor is called. However do note here that name variable is static and can even be accessed as Child2.name. And thus no exception is raised.

Your Child3 class has a constructor has a constructor thus parent constructor is never called and thus check for presence of name is actually never made. So you do need to add following line to to child constructor.

super().__init__()

This call shall be made after declaring name if constructor defines name. And this is what you have done in your Child5 class.

For exactly the same reason as above, exception was not captured in Child4. Following will check this condition in Child4:

class Child4(Parent):
    def __init__(self):
        super().__init__()

You can check when constructor is being called, by simply adding a unique print statement(such as print(1), print(2), and so on) in each constructor (preferably at the beginning).

Upvotes: 1

Related Questions