Force child class to call parent method when overriding it

后端 未结 7 1926
梦谈多话
梦谈多话 2020-12-15 16:05

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

相关标签:
7条回答
  • 2020-12-15 16:44

    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.

    0 讨论(0)
  • 2020-12-15 16:48

    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.

    0 讨论(0)
  • 2020-12-15 16:54

    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
    
    0 讨论(0)
  • 2020-12-15 16:58

    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.'
    
    0 讨论(0)
  • 2020-12-15 16:58

    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.

    0 讨论(0)
  • 2020-12-15 17:00

    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!
    
    0 讨论(0)
提交回复
热议问题