Python入门精华OOP调用父类的方法及MRO方法解析序列
在继承关系中,我们想调用已经被覆盖了的父类的方法,就需要如下实现:
解决方法:
要调用父类中的方法,就要使用超类(超集)方法super(),该方法旨在调用已经被覆盖的父类的成员方法。class Aclass: def __init__(self): self.a = None def prtInfo(self): print("hello world!") class Bclass(Aclass): def __init__(self,b): self.b = b super().__init__() #调用父类的构造函数,保证父类被正常的初始化了 def prtInfo(self): print("hello python") super().prtInfo()
讨论:
有关python是如何实现继承的?
针对每一个定义的类,都会计算出一个成为方法解析顺序(MRO)的元组,其只是简单的对所有基类进行简单地线性排列。class Base: def __init__(self): print("Base.__init__") class A(Base): def __init__(self): super().__init__() print("A.__init__") class B(Base): def __init__(self): super().__init__() print("B.__init__") class C(A,B):#多重继承 def __init__(self): super().__init__() print("C.__init__") c = C() #结果为: """ Base.__init__ B.__init__ A.__init__ C.__init__ """ print(C.__mro__)#调取C类的MRO表 #结果为: """ (, , , , ) """
通过上述的C类调用MRO表,我们不难看出,它将本类开始一直到object类直接所有的父类一次性从左向右逐层向上的排列了出来(先排列自己,在排列自己的父类,最后排列父类的父类,以及最后的object)
然而MRO为何如此排列,这里要涉及到一个非常令人讨厌的数学算法,C3线性化处理,这里只是总结其三个约束:(简单点说,其实就是对父类进行归并排列)
1、先检查子类,再检查父类
2、有多个父类时,按照MRO表的顺序依次查看
3、如果下一个待选的类出现了两个合法的选择,那么就从第一个父类中选取。
4、补充一点:MRO对类的排序几乎适用于任何定义的类层次结构。
来了来了,它真的来了:重点~~
有很多同学是否仔细看过上边的代码?class C(A,B):#多重继承 def __init__(self): super().__init__() print("C.__init__") #为何输出结果是: """ Base.__init__ B.__init__ A.__init__ C.__init__ """ #按照上述概念不觉得是: """ Base.__init__ A.__init__ B.__init__ C.__init__ """#或者除了正确结果以外的所有结果更为合适??(只要不是正确结果都是对的)
有关super()函数,以下重点需要各位明白:
在重写的方法中仅使用一次super()方法时,会按照MRO表从下一个类开始搜索对应的方法或属性,以此类推。 所以C中重写了父类的构造,构造中有super,所以会按照顺序去查找MRO中下一个类的方法,发现A中也有super,就会再去B中找对应的方法(同名方法是__init__),所以找到B的构造,可是B中又有super,就会再去MRO中B的下一个类(Base)中找对应的方法(Base的__init__()方法),所以会先打印"Base.__init__",打印完后又因为B的__init__中还有打印"B.__init__",所以接着打印‘B.__init__’,又因为打印完后A中还有打印"A.__init__",所以再打印"A.__init__",最后打印"C.__init__"。这样就可以遍历MRO整张表中所有的对应的__init__()方法,并且让每个方法只会被调用一次。
为了更好的记忆:当所有重写的方法中只使用了一次super函数时,会从最上层的类依次调用其指定的方法即可以理解为(object->Base->B->A->C)。
所以,输出结果为:""" Base.__init__ B.__init__ A.__init__ C.__init__ """
甚至于如下情况更为耐人寻味,仔细品一品:class A: def prt(self): print("A") super().prt() class B: def prt(self): print("B") class C(A,B): pass c = C() c.prt() #c.prt()的打印结果为: """ A B """ print(C.__mro__)#(, , , )
值的一提的是:AB均没有显式的继承的父类,为何结果为打印‘AB’呢?这里就要理解MRO的含义了哦!