class A:
def __init__(self):
self.j = 0
self.calc_i(865)
def calc_i(self, i):
self.i = 68 * i
class B(A):
def __init__(self):
super().__init__()
print("i from B is", self.i)
def calc_i(self, i):
self.i = 37 * i
b = B()
The Code above should call the parent class method of calc_i according to my understanding because the parent class will run it's own method and it also doesn't know where it is being used as a parent.
But When I run it, it calls the child method where i * 37 and not the parent method
CodePudding user response:
because the parent class will run it's own method
No, it won't.
When B.__init__
calls super().__init__
, it's the same instance of B
that gets passed to A.__init__
. As a result, the evaluation of self.calc_i
uses the method resolution order (MRO) of B
, not A
, to determine which calc_i
method gets called. Because the MRO is [B, A, object]
, and B
defines calc_i
, that's the method invoked by self.calc_i(865)
.
The most important thing to remember when writing method is that you don't know the runtime type of self
. The only thing you can be reasonably sure of is that type(self)
will be a subclass of A
, and you can't predict what methods that subclass will define.
If you absolutely need A.__init__
to call A.calc_i
, you need to be explicit:
def __init__(self):
self.j = 0
A.calc_i(self, 865)
or, define a method whose name makes it absolutely clear it should not (and cannot without some effort) be overridden.
def __init__(self):
self.j = 0
self.__calc_i(self, 865)
def __calc_i(self, i):
self.i = 68 * i
If you want some uses of calc_i
to be overridable, you can define
def calc_i(self, i):
return self.__calc_i(i)
and use self.__calc_i
when it must be A
's private implemeantion, and self.calc_i
where you are OK with a subclass providing its own.