我们用代码来解释这个结论
我们先来看一个基础的代码。
class A:
i = 10
def sum(self):
return self.getI() + 10
def sum1(self):
return self.i + 10
def getI(self):
return self.i
class B(A):
i = 20
def sum(self):
return self.i + 20
def getI(self):
return self.i
def sum1(self):
return self.i + 10
b = B()
print(b.sum()) # 40
print(b.sum1()) # 30
我们将类B()实例化,创建一个对象b,调用该对象的sum方法,由于类B()中含有sum方法,则直接调用即可,该行代码输出40。同理,B类中也存在sum1方法,则直接调用即可,返回30。
将上面的代码中B类的sum方法和sum1方法删掉,如下所示,那么程序会输出什么呢?
class A:
i = 10
def sum(self):
return self.getI() + 10
def sum1(self):
return self.i + 10
def getI(self):
return self.i
class B(A):
i = 20
def getI(self):
return self.i
b = B()
print(b.sum()) # 30
print(b.sum1()) # 30
同样,b对象调用B类中的sum方法,由于B类中没有sum方法,但又因为B类与A类构成继承关系,且A类中有sum方法,因此在执行b.sum()时会调用A类中的sum方法,A类中的sum方法返回的是 self.getI()+10,由于A类、B类中都存在getI()方法,那么此时,调用的是哪个类中的 getI() 方法呢?这就引出了我们的结论:当调用对象成员的时候,会和对象本身动态关联,它调用哪个类中的getI()方法,主要取决于self是哪个类型,那么我们就可以知道,此时这个self表示的就是B类这个类型,因此调用的这个getI()方法就是B类中的getI()方法,那么此时会返回30。
同理可分析第二个print语句。
我们使用PyCharm来验证一下我们的猜想
在第一个print语句处打上断点,即第21行语句,我们开始进行Debug。
程序迅速执行到第20行处停止,如下图所示。接下来我们按下Step Into按键进行逐步调试。
我们可以看到程序迅速跳转到第四行,准备执行A类中的sum方法,这与我们前面设想的一致
并且我们清晰的可以看到,此时的self类型是B类型。
接下来,我们再次进行Step Into,我们可以看到程序跳入到B类中的getI方法。如下图所示。这与我们在前面的猜想一致。
经过验证,我们的猜想是正确的。