我们知道,继承是面向对象编程中一个非常重要的概念。子类可以使用父类的方法和属性。例如下面的代码:)defsay(self):print('我是儿子')son=Son()print(son.address)运行效果如下图所示:从图中可以看出,子类没有有self.address这个属性,但是当我们直接打印的时候,不会报错,它会自动使用父类的address属性。显然,如果某个属性没有子类或父类,就会报错,如下图:我们也知道Python支持多重继承,一个子类可以有多个父类。所以,请看下面的代码:):print('我现在住:',self.address)classSon(GrandFather,Father):def__init__(self):super().__init__()defsay(self):print('我是儿子')son=Son()son.where()运行效果如下图所示:仔细观察会发现这段代码有点奇怪。我调用了son.where()方法。由于Son类没有这个方法,所以会去它的两个父类中寻找。所以我在父类中找到了它。于是执行Father中的where()方法,至此没有问题。但是后来出了点问题,在.where()方法中,调用了self.address属性。但问题是Father类没有.address属性!而Father没有父类,那么.address属性从何而来呢?难道在开发者不知道的某个隐蔽角落,GrandFather类已经悄悄变成了这样,GrandFather不仅是C的父类,还是C的父类的父类?祖父既是父亲又是祖父?实际上,并没有这种令人困惑的关系。要解释这一现象,还得从自我说起。我们知道类的属性都是以self开头的,方法的第一个参数也是self。那么这个自己是什么?下面用一小段代码看看是什么:classA:defget_self(self):returnselftest=A()what_is_self=test.get_self()testiswhat_is_self运行效果如下图所示:从图中可以看到里面,self其实就是这个类的一个实例。我们看一下继承的情况:如图,虽然我在A类的.get_self()方法中返回了self,但是这个self其实是B类的一个实例。因为我从头到尾只初始化了B类,并没有初始化A类。A是B类的父类。但是父类的self会成为子类的一个实例。明白了这一点,前面的问题就很好解释了,再打印一些信息:大家注意画红线的地方,self永远是Son类的一个实例。因此,.address在初始初始化时,是初始化Son实例的.address属性。之后在.where中调用.address时,也会读取Son实例的.address属性。所以不会出现Father类读GrandFather类的情况。自始至终,Son类的实例都在进行各种操作。因此,在本例中,当使用继承时,父类的所有属性和方法,如果子类重名,则以子类为准。如果没有定义子类,那么父类的属性和方法实际上会转到子类中。所有看似由父类执行的操作,实际上都是由子类执行的。上面的代码甚至可以近似等价于:由于子类中定义了say方法,所以子类重写了父类。以子类的say方法为准。子类中没有定义where和address,所以Father类的where方法和GrandFather中的address属性会直接到子类中去。
