I have a base class and a sub class. In the base class I have an instance method which is called in __init__
. In the sub class I have overridden this method. The super()
call in the sub class does not call the original base method but the overridden sub class method. Why?
class BaseClass:
def __init__(self, value):
self.value = value
self.transformed_value = self.create_value(value)
def create_value(self, value):
print("base")
return value + 1
class SubClass(BaseClass):
def __init__(self, value):
super().__init__(value)
def create_value(self, value):
print("sub")
return value + 2
s = SubClass(3)
I expect the print output to be "base", but the actual output is "sub". How can I modify the code to get "base" without explicitly calling BaseClass.create_value(self, value)
in the __init__
of BaseClass
?
Python is dynamically typed. That means when you write
def __init__(self, value):
self.value = value
self.transformed_value = self.create_value(value)
is doesn't matter which class that method belongs to when evaluating self.create_value
: it only matters what the type of self
is when the method is called.
When you call SubClass(3)
, you eventually call SubClass.__init__
, which immediately calls BaseClass.__init__
with an argument of type SubClass
. Since SubClass.create_value
is defined, that's what self.create_value
resolves to.
If, for whatever reason, you insist the BaseClass.__init__
calls BaseClass.create_value
on its self
argument, you have to do so explicitly with BaseClass.create_value(self, value)
. However, that's rarely a good idea. If the type of self
wants a method it overrides to be called, that's its responsibility to do so, by using super
itself:
def create_value(self, value):
rv = super().create_value()
print("sub")
return value + 2 # Or perhaps do something with rv first?
Further to add to @chepner's elegant answer, if you want the parent class to call it's own method, you may modify the parent class as below:
class BaseClass:
def __init__(self, value):
self.value = value
self.transformed_value = self.base_create_value(value) # use the renamed reference
def create_value(self, value):
print("base")
return value + 1
base_create_value = create_value # create a local reference to the method
In the above BaseClass
, we are creating a simple reference to a parent method and are using the same inside its own __init__
method. By doing so, we can continue to make use of this reference object even if the base class' method is overridden and when it is called by the child instance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With