00:00
那从现在开始,我们继续来讲解一下关于继承的问题,在上一小节中为大家讲解了一下多继承以及零星继承的bug,对不对?那么我们要在本小节当中为大家解决一下菱形集成的bug,好了,打开我们的排差,然后呢,上一节课我们说了菱形集成的bug所在的问题是什么呢?给大家看一眼啊,人生技能bug所在的问题就是我们同一个方法,特别是顶级的那个方法,可能会被调用多次,对不对?那怎么办呢?来,通过上节课的图片我们可以看出一些端倪,来哈,来,打开我们这个菱形继承,这是上节课我们画的菱形继承的一个图片。啊,打开有个麦稍微等一下啊好吧。好。那我们看到了ABCD4类所形成的菱形关系中,在D类调用某个BC类同有的方法,并且BC类也继承A类方法的时候呢,就会导致A类中的那个方法被调用多次,是不是?所以bug就在这儿,那我们怎么样来解决这个问题呢?大家想一想,如果说这不是一个什么呀,菱形继承,而是一个简简单单的一个单继承,还会有这个问题的所在吗?也就是说如果啊,我们的菱形继承这个关系是不存在的,而取而代之的,或者叫做现在我们面前摆出的类是什么形状呢?是ABCD4根竖着排列啊,也就是说我们如果这四个类过程中啊,四个类是这种关系的啊。
01:28
A类,然后呢,B类我复制一下啊B类。然后呢,C类和D类,如果这四个类形成的关系不是现我们刚刚画菱形继承的关系,而是什么呢?而是另外一种形态,什么形态呢?单继承的过单继承的格式,它还会存在我们刚刚所说的同样的A类中的方法可加两次吗?答案是不会的,因为在这里边如果说它的结构是一个单继承的结构,就是D类继承C类,C类继承B类,B类继承A类的话,如果是这种结构,它就不存在于两个类同时使用A类中一个方法的问题,对不对?所以呢,解决它的方案,或者叫做零星继承的解决方案,就是干什么事呢?
02:19
把它变成这种单基层结构啊解决方案。方案。解决方案就是将我们的菱形继承啊改变成类似单继承的关系,用这种关系就可以避免菱形继承带来的多次调用某一个方法的一个问题,所的这个方式啊,那怎么来变呢?首先这个菱形继承啊,已经是铁板上钉钉的事情了,菱形继承已经是板上钉钉的,为什么呢?因为在你的代码里边注意看好了,这是我们上次写的类好不好,我们给它复制一份出来行不行,CTRL加a ctrl加C啊,然后你在里边我们写一下我们菱形进成的第二个文件啊,In herer可能写错词了,In bug2啊,我们来解决这个问题,好吧,把第一个文件呢代代码全都粘过来。
03:16
为什么我们,哎怎么说啊,靠左歪了啊,为什么说我们刚刚这个零星继承是板上钉钉的事情呢?很简单,因为在这个学代码里边,你确实是什么呀,这么写的A类,一个B类集成A类,然后C类集成A类,对不对,然后D类集成了我们的VC类,所以这个是改不了的,那我们能改变的是什么东西呢?哎,调用的时候我们是可以改变的,看到没有,我们以前调用方法的时候怎么调用的,是不是直接写上类名,加上它对应的方法名霸不对,那如果用这种方式的话,其实就是延续了菱形继承的一个关系啊,那我们不使用这个,我们希望能够把菱形继承的关系把它修改或者是突破,改成单继承的关系来调用,是不是就可以了,那怎么做呢?来看好了,返回我们的代码当中,将这里边所有调用的方法全部删掉,也就是说我们不再使用类的方式。
04:17
来调用了明白,把所有类调用的方式全部删掉。全部删掉,那么这个时候大家来看啊,首先呢,这四个类还在那摆着,动物类,人类,然后鸟类,嗯,海鸟类,它们的寄承关系我也没变,唯一改变的是我取消了BCD类中调用分类方法的这个功能,是不是全都留空了,全都留空了对不对,好了。当我们把它留空之后,诶,很多说那就能这样,那就能变成这个单继承的关系吗?不是啊,继承关系还是那样多继承,菱形继承没有改变,但是调用的时候我们可以让它改变,也就说我们可以按照这种方式来调用,那这怎么调用啊,看不懂啊,完全看不懂啊。好在这里边如果你希望一个菱形集成按照单继承的格式来调用的话,我们可以在这里边抛弃我们的什么呢?类名调用方式,直接使用super括号,点加上方法名就可以了。
05:12
看懂了吗?这种方式。就不叫调用父类中的发音功能,而是调用什么呢?而是调用MRO表,MRO列表中的上一层类的发音功能。所有的调用父类的功能,我们通改成这个,包括这个人类的,包括这个鸟类的呀,包括下面这个调用人类和鸟类的,我们通通不再使用它,通通改变成这个方式。调ML列表里边的上一层类的发音功能,这个时候大家再来看啊,我现在给大家看的是结果,因为我们还没告诉原理对不对?右键运行一下这个程序,你会发现啊鸟人类在说话,然后呢,调用了人类的发音功能,也调了鸟类的发音功能,同时我们惊喜的发现人类这个动物类的发音功能是不是只理解了一次,是不是解决了问题,诶,所以解决问题的方式我已经写出结果了,但是大家不明白的是哦,为什么这样就解决了呢?好了,告诉大家啊,我们Python当中有一个东西,什么东西呢?叫做MRO列表。
06:25
来,我们在这里边新建一个文件给大家看一下行不行,不用新建,直接在上一个文件里写吧,行不行,就是我们这个单机乘与多基层里边的。好,那在这里写上啊,菱形,菱形几成的bug解决用到的就是MRO列表和我们的super这个对了,人家不是一个方法,是一个类啊和super这个类啊和super类,好为什么这么说呢?好,首先呢,当我们啊,当我们定义一个菱形什么呢?继承关系的时候,我们的程序啊,程序会自动生成一个新的什么呢?MRO列表,这里边就涉及到啥叫MRO列表啊,列表官方名称叫做什么呢?模测的。
07:21
啊,就是方法啊,Ma method relation啊,Relation怎么写英文单词关系啊,那个relation I I什么来着。呃,叫re吧,Reon啊就是关系,Ion关系,然后呢,这个O就是order order list,或者叫order啊,什么意思呢?它叫做方法关系列表,简单的就是说啊,当你定义这么个菱形继承的时候呢,程序会帮你生成一份类似于单继承的这么一个列表,这个列表里放的是什么呢?就把你的类啊,按照单继承的方式放到了一起。
08:01
这个表就叫做MRO列表,这个表就叫做MRO列表,当然大列表啊,大家会有疑问哈,它怎么怎么摆成这样的呢?在这里边我可以教大家一下它的摆放原理啊。M列表首先呢,需要注意RO列表,MRO列表它的生成啊的生成采用了什么呢?C3算法啊,C3算法,这是我们Python内置的一个算法,采用C3算法来进行完成的,完成的它的原则,呃,C3算法,C3算法的原则非常简单,你不需要知道它里边的算法怎么实现的,我只告诉你原则或者叫原理,你就知道了。它最后生成的MR列表是什么样的,什么原理呢?第一条原理叫做子类写错了,子类永远在父类的前面。所以在这张图里边啊,由于什么呀,ABC相对D来说,D是子类,对不对?所以在什么事呢?在MR列表里边是这么排的,看好了啊,是子类在父类的前面,是D类在最开始。
09:08
看到了吧,B类完了之后干什么事呢?A类一定是在最后啊,A类一定是在最后,因为子类在父类的前面嘛,问题就在于B类和C类该怎么放,是不是B类和C类该怎么放,到底是先放B类还是先放C类啊?B类啊,C类先放谁呢?这个取决于另外一个东西啊,B类和C类的摆放顺序则是原则中的第二条,第二条原则是什么呢?来给大家看,第二条原则是什么呢?叫做同意,等写错了啊,叫同一等级的来同意。等级的类按照什么呢?子类中的继承顺序摆放,也就是说在嗯摆放写错了,摆放也是在继承当中啊,你把B类放前面,那么列表里B也在前面,然后你在继承里C放前面,那那继承列表里C也在前面,所以AB这个bcda的类到底是怎么摆放,可以确定是A和D,它一定是D在前,A在后,B和C摆放就看一下D类的继承里边先写的B还是写C,先写BB在前面,先写CC在前面,然后反过来看什么呢?看我们刚刚写的这个真实的代码,在这个真实代码当中啊,你看一下什么呢?鸟人类,鸟人类是不是写了BC类的继承,就是我们的人类和鸟类的继承,其中人类在前面,鸟类在后面,这就意味着按照我们的什么呢?按照我们的刚刚C3算法啊。
10:42
它最终形成的列表应该是这个样子的啊。把它删掉啊。长价好,这个C,这个MRO列表来,MRO列表它最后长的什么样呢?按照我们的推算结果应该是这样的,首先子类一定在父类前面,所以最后一个类啊,这第一个类一定是birdman类,鸟人类是最下面那一层嘛,说不是子类,然后呢,可以确定的是最后一个一定是谁呢?一定是它的共同负类,也就是animal类。
11:13
Animal类对不对?Animal类那中间有有谁啊,有鸟类和人类这么两个类,咱说了按照谁呀,按照这个子类当中的摆放顺序,把鸟类和人类拿出来就可以了,就这么个顺序。看见了吗?然后他们之间使用逗号分开啊,最后成立一个什么呢?一个容器类数据,其实也就是列表的一个格式,这个列表就称之为RO列表,也就是把你的菱形继承改成这种单继承的顺序啊,但是其实你这样写还有一个小小偏差,为什么呢?别忘了任何一个类都有负类的,Animal类的负类是谁?Object啊,所以人家上面实际还有个object。也就是说这样的话,我们就可以根据这个算法的原则,或者这个东西啊,来推算出MR列表,然后呢,干什么事呢,你的super它在用的时候。
12:01
Super是怎么玩的呢?来看好了,首先up super调用的时候啊,调用的时候它不是查找负类,这个千万记住啊,因为我们之前刚开始学那个继承的时候,确实说了修是查找负类用的,对不对,但是呢,我也说了暂时,但实际上实际上啊写错了。实际上我们的super是查找什么呢?RO写错MRO列表的上一个类啊,好了,那再返回我们代码中来看一下啊,那你看我们这里边都写super了,对不对?当你调用鸟儿类的时候,它找super,那应该找什么呀?鸟类的上一个,鸟类的上一个是不是人类是不是,也就说先调上鸟类,再调上人类,人类完了之后,你看找人类啊,人类的super啊,人类的super找他的上一个是谁?是我们这个,呃。在哪呢?是鸟类是不是过来找了一下你的鸟类,鸟类是不是找鸟类的这个操作对不对?鸟儿类也用的super,那是不是鸟类super找是吧?鸟类的上一个鸟类上一个是动物类,所以找到了animal的思维方法是不是啊就呵这样的话是不是就是把一个零集是变成了一个单基成的的结构对不对?好然后呢,我们的预算就是完全没有问题的一个程序了,Animal只会被调用一次是不是,所以这就是菱形进常当中的一个解决问题,就是用super来代替类名,并且需要注意啊,需要注意什么呢?
13:32
Super这个玩意儿啊,它调用对象方法的时候,对象方法的时候不需要啊,写错了不需要传入对象,它会自动传入的,自动传入的,因为你大家也看我代码里面了,我明明写着对象方法调用了上一个类里上一个里边的C,却没有传任何东西,是不是这个S会自动传进去啊,所以你不用管这个事情,那么这样一来的话,我们L列表也被大家介绍完了,Super也介绍完了啊,Super的这个使用功能也给大家介绍完了,当然super还有一些很多其他用法,我们后再遇到的时候再给大家介绍行不行?好了,在这里边啊,还有一句话给大家说一下,就super它不是一个函数啊,大家看super觉得是个函数,实际上super是程序中已经存在的一个类啊,来看一下吧,实际看看super啊,你直接print super就可以了,它是存在的,这系统直接给我们提供的一个玩意儿啊,来右监狱写一遍,走你你看一下是不是直接出来一个类super,所以super你别看它是。
14:32
小写的,但它确实是一个类啊,Super是一个类啊。是个类,这个要注意啊,万一哪天考试的时候说super是super加括号,是不是这个函数啊,告诉他不是啊,Super加括号实际上是一个类的实例化操作,OK,那接下来的话,大家看到我们的菱形继承bug是不是就解决了?好了,感谢大家收看菱形继承bug介绍完成,我们下一小节再见。
我来说两句