Search code examples
pythonpython-3.xinheritancemethodssubclass

Redefining methods through class inheritance in Python


I'm playing around with class inheritance and I'm wondering if its possible to change aspects of an inherited method in the child class without having to rewrite the whole thing?

For example:

class Parent:
    def _init_(self, x):
        self.x = x

    def foo(self):
        a = self.x
        if a > 0:
            forward = True
        elif a < 0:
            forward = False
        return forward

class Child1(Parent):
    def foo(self, y=None, bool=False):
        if bool:
            a = y
        else:
            a = self.x
        super().foo()

class Child2(Parent):
        pass

What I'm looking for is if I called Child1.foo it could reassign the variable a before running through the method, as defined in the parent class. Where a is dependent on the y and bool arguments passed through the rewritten method in Child1:

print(Child1(2).foo(-2, True))
# => False
print(Child1(2).foo())
# => True
print(Child2(2).foo())
# => True

Is this possible, or would I just have to rewrite a new method for each class?


Solution

  • I think I understand your problem and I have some suggestions for how you can resolve this:

    Using "private" methods

    For example:

    class Parent:
        def __init__(self, x):
            self.x = x
    
        def _foo(self, a=None):
            a = a if a else self.x * 2  
            
            if a > 10:
                over = True
            else:
                over = False
    
            return over
    
        def foo(self):
            return self._foo()
    
    class Child1(Parent):
    
        def foo(self, y=None, condition=False):
    
            if condition:
                a = y*2
            else:
                a = self.x*2
    
            return self._foo(a)
    
    class Child2(Parent):
        pass
    
    

    In this example, all child classes will inherit the _foo "private" function, where they may or may not receive a value of a.

    Using abstract classes

    There is another solution to this problem with abstract classes (here is an example of how to do this), where you forces the child class to implement the function foo:

    Important

    Remembering that in the case of abstract classes, if you do not define the function decorated with @abstractmethod, you will receive an error similar to this TypeError: Can't instantiate abstract class Child2 with abstract methods foo

    Example:

    Python 2.x

    from abc import ABCMeta, abstractmethod
    
    class Parent:
        __metaclass__ = ABCMeta
    
        def __init__(self, x):
            self.x = x
    
        def _foo(self, a=None):
            a = a if a else self.x * 2  
            
            if a > 10:
                over = True
            else:
                over = False
    
            return over
    
        @abc.abstractmethod
        def foo(self):
            pass
    
    class Child1(Parent):
    
        def foo(self, y=None, condition=False):
    
            if condition:
                a = y*2
            else:
                a = self.x*2
    
            return self._foo(a)
    
    class Child2(Parent):
    
        def foo(self):
            return self._foo()
    

    Python 3.x

    class Parent(metaclass=ABCMeta):
    
        def __init__(self, x):
            self.x = x
    
        def _foo(self, a=None):
            a = a if a else self.x * 2  
            
            if a > 10:
                over = True
            else:
                over = False
    
            return over
    
        @abc.abstractmethod
        def foo(self):
            pass
    
    class Child1(Parent):
    
        def foo(self, y=None, condition=False):
    
            if condition:
                a = y*2
            else:
                a = self.x*2
    
            return self._foo(a)
    
    class Child2(Parent):
    
        def foo(self):
            return self._foo()
    

    In both examples you will have the same result by running this:

    print(Child1(2).foo(10, True)) // True
    print(Child1(2).foo()) // False
    print(Child2(2).foo()) // False