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