I am curious whether there is a way in Python to force (from the Parent class) for a parent method to be called from a child class when it is being overridden.
Examp
Very little in Python is about forcing other programmers to code a certain way. Even in the standard library you will find warnings such as this:
If the subclass overrides the constructor, it must make sure to invoke the base class constructor before doing anything else to the thread.
While it would be possible to use a metaclass to modify subclasses' behavior, the best it could reliably do in this case would be to replace the new methods with yet another method that would take care of calling both the replaced method and the original method. However, that would have problems if the programmer then did call the parent method in the new code, plus it would lead to bad habits of not calling parent methods when one should.
In other words, Python is not built that way.
However, is there a way to force developers that develop Child classes to specifically call(not just override) the 'start' method defined in the Parent class in case they forget to call it
In Python you can not control how others override your functions.
All you need is super.
With it, your code could look like this:
class Parent(object):
def __init__(self):
self.someValue = 1
def start(self):
self.someValue += 1
class Child(Parent):
def start(self):
# put code here
super().start()
# or here
With some metaclass hacks, you could detect at runtime whether the parent start has been called or not. However I will certainly NOT recommand using this code in real situations, it's probably buggy in many ways and it's not pythonic to enforce such restrictions.
class ParentMetaClass(type):
parent_called = False
def __new__(cls, name, bases, attrs):
print cls, name, bases, attrs
original_start = attrs.get('start')
if original_start:
if name == 'Parent':
def patched_start(*args, **kwargs):
original_start(*args, **kwargs)
cls.parent_called = True
else:
def patched_start(*args, **kwargs):
original_start(*args, **kwargs)
if not cls.parent_called:
raise ValueError('Parent start not called')
cls.parent_called = False
attrs['start'] = patched_start
return super(ParentMetaClass, cls).__new__(cls, name, bases, attrs)
class Parent(object):
__metaclass__ = ParentMetaClass
def start(self):
print 'Parent start called.'
class GoodChild(Parent):
def start(self):
super(GoodChild, self).start()
print 'I am a good child.'
class BadChild(Parent):
def start(self):
print 'I am a bad child, I will raise a ValueError.'
This does not relate directly to Python, it would be the case for most OO languages. You should define an abstract method in your base class, make it non-public (but available for overriding by subclasses) and also create a public template method in the parent class, that will call this abstract method (defined in your subclass). The client code will not be able to call the method in question directly, but will be able to call the template method which, in turn, will make sure that the method in question is called in the correct order/context.
In other words, your system must not depend on the subclasses calling parent's implementation. If that is a must, then you indeed should review your implementation and decompose the method in question (eg, use the template method pattern).
Also, some languages (like Java) implicitly call the parent's constructor, if the subclass'es constructor does not do it explicitly (does not work for plain methods though).
In any case, please never rely on "hacks". that is not the right way to solve problems.
If the class hierarchy is under your control, you can use what the Gang of Four (Gamma, et al) Design Patterns book calls the Template Method Pattern:
class MyBase:
def MyMethod(self):
# place any code that must always be called here...
print "Base class pre-code"
# call an internal method that contains the subclass-specific code
self._DoMyMethod()
# ...and then any additional code that should always be performed
# here.
print "base class post-code!"
def _DoMyMethod(self):
print "BASE!"
class MyDerived(MyBase):
def _DoMyMethod(self):
print "DERIVED!"
b = MyBase()
d = MyDerived()
b.MyMethod()
d.MyMethod()
outputs:
Base class pre-code
BASE!
base class post-code!
Base class pre-code
DERIVED!
base class post-code!