Home > Software engineering >  Inheritance: How to make parent method work with other parent methods?
Inheritance: How to make parent method work with other parent methods?

Time:05-31

So I have two classes, where one inherits from another and overrides all parent methods:

class Parent:
    def name(self):
        return 'parent'

    def run(self):
        print(f'calling method from parent: I am {self.name()}')


class Child(Parent):
    def name(self):
        return 'child'

    def run(self):
        print(f'calling method from child: I am {self.name()}')
        return super().run()

Running the following piece Child().run() triggers method run both for child and parent, and the output is:

calling method from child: I am child
calling method from parent: I am child

And result is clear - since we have redefined method name, new version is used in both run methods. (I am child on both lines)
And that's the main problem - the way I want it to work is for parent run method to use parent name.

What I have accomplished so far is replacing super with self.__class__.__mro__[1], so that method looks like

def run(self):
    print(f'calling method from child: I am {self.name()}')
    return self.__class__.__mro__[1]().run()

The way it works is it gets parent class using method resolution order and creates instance of parent class. It works fine and now result is:

calling method from child: I am child
calling method from parent: I am parent

But I don't like this solution:

  • Single inheritance - since we hardcode parent class index, we cannot make it work with several parent classes
  • Using MRO doesn't feel right for this case
  • Here we assume __init__ doesn't take extra arguments

I think clue is in changing self.name in parent method so that it will use parent method explicitly, but I don't know how to achieve this.

CodePudding user response:

You can find the current class that the method is defined in by using __class__:

class Parent:
    def name(self):
        return 'parent'

    def run(self):
        print(f'calling method from parent: I am {__class__.name(self)}')

CodePudding user response:

I'd suggest making name a name-mangled (__) attribute that's private to the class:

class Parent:
    __name = 'parent'

    def run(self):
        print(f'calling method from parent: I am {self.__name}')


class Child(Parent):
    __name = 'child'

    def run(self):
        print(f'calling method from child: I am {self.__name}')
        return super().run()

Child().run()
# calling method from child: I am child
# calling method from parent: I am parent
  • Related