美文网首页
python 多重继承的事

python 多重继承的事

作者: 5698450330c9 | 来源:发表于2018-08-28 22:45 被阅读0次

什么是多重继承

继承是面向对象编程的一个重要的方式,通过继承,子类就可以扩展父类的功能。和c++一样,在python中一个类能继承自不止一个父类,这叫做python的多重继承(Multiple Inheritance )。多重继承的语法与单继承类似

class SubclassName(BaseClass1, BaseClass2, BaseClass3, ...):
    pass

当然,子类所继承的所有父类同样也能有自己的父类,这样就可以得到一个继承关系机构图如下图所示:

inheritance.jpg

钻石继承(菱形继承)问题

多重继承容易导致钻石继承(菱形继承)问题,关于为什么会叫做钻石继承问题,看下图就知道了:

diamond.jpg

在python中,钻石继承首先体现在父类方法的调用顺序上,比如若B和C同时重写了A中的某个方法时:

class A(object):
    def m(self):
        print("m of A called")

class B(A):
    def m(self):
        print("m of B called")
    
class C(A):
    def m(self):
        print("m of C called")

class D(B,C):
    pass

如果我们实例化D为d,然后调用d.m()时,会输出"m of B called",如果B没有重写A类中的m方法时:

class A(object):
    def m(self):
        print("m of A called")

class B(A):
    pass
    
class C(A):
    def m(self):
        print("m of C called")

class D(B,C):
    pass

此时调用d.m时,则会输出"m of C called",那么如何确定父类方法的调用顺序呢,这一切的根源还要讲到方法解析顺序(Method Resolution Order,MRO),这一点我们等会再将。

钻石继承还有一个问题是,比如若B和C中的m方法也同时调用了A中的m方法时:

class A:
    def m(self):
        print("m of A called")

class B(A):
    def m(self):
        print("m of B called")
        A.m(self)
    
class C(A):
    def m(self):
        print("m of C called")
        A.m(self)

class D(B,C):
    def m(self):
        print("m of D called")
        B.m(self)
        C.m(self)

此时我们调用d.m,A.m则会执行两次。

m of D called
m of B called
m of A called
m of C called
m of A called

这种问题最常见于当我们初始化D类时,那么如何才能避免钻石继承问题呢?

super and MRO

其实上面两个问题的根源都跟MRO有关,MRO(Method Resolution Order)也叫方法解析顺序,主要用于在多重继承时判断调的属性来自于哪个类,其使用了一种叫做C3的算法,其基本思想时在避免同一类被调用多次的前提下,使用广度优先和从左到右的原则去寻找需要的属性和方法。当然感兴趣的同学可以移步:MRO介绍.

比如针对如下的代码:

>>> class F(object): pass
>>> class E(object): pass
>>> class D(object): pass
>>> class C(D,F): pass
>>> class B(D,E): pass
>>> class A(B,C): pass

当你打印A.__mro__时可以看到输出结果为:

(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.E'>, <class '__main__.F'>, <class 'object'>)

如果我们实例化A为a并调用a.m()时,如果A中没有m方法,此时python会沿着MRO表逐渐查找,直到在某个父类中找到m方法并执行。

那么如何避免顶层父类中的某个方法被执行多次呢,此时就需要super()来发挥作用了,super本质上是一个类,内部记录着MRO信息,由于C3算法确保同一个类只会被搜寻一次,这样就避免了顶层父类中的方法被多次执行了,比如针对钻石继承问题2中的代码可以改为:

class A(object):
    def m(self):
        print("m of A called")

class B(A):
    def m(self):
        print("m of B called")
        super().m()
    
class C(A):
    def m(self):
        print("m of C called")
        super().m()

class D(B,C):
    def m(self):
        print("m of D called")
        super().m()

此时打印的结果就变成了:

m of D called
m of B called
m of C called
m of A called

结论

多重继承问题是个坑,很多编程语言中并没有多重继承的概念,毕竟它带来的麻烦比能解决的问题都要多,所以如果不是特别必要,还是尽量少用多重继承。如果你非要用,那你要好好研究下类的层次结构,至少要对C3算法具有一定的了解吧,比如弄懂下面的代码哪里出了问题?

>>> F=type('Food',(),{'remember2buy':'spam'})
>>> E=type('Eggs',(F,),{'remember2buy':'eggs'})
>>> G=type('GoodFood',(F,E),{}) 
# TypeError: Cannot create a consistent method resolution
# order (MRO) for bases Food, Eggs

相关文章

  • 面向对象

    类的定义方法 子类的定义 多重继承 python允许多重继承。

  • Python多重继承(拓扑排序)(9)

    Python跟Java不同,Java只能单继承(不过有多实现),而Python能够多重继承。其多重继承遵循拓扑排序...

  • python 多重继承的事

    什么是多重继承 继承是面向对象编程的一个重要的方式,通过继承,子类就可以扩展父类的功能。和c++一样,在pytho...

  • Python:12多重继承

    python 多重继承之拓扑排序

  • 面向对象高级编程(二)-多重继承&定制类

    多重继承 继承是面向对象编程的一个重要方式,通过继承,子类可以扩展父类的功能。 在python中,可以通过多重继承...

  • 当心掉进Python多重继承里的坑

    关于类的知识点里面,有一块是关于多重继承,跟其他主流语言一样,Python也支持多重继承,多重继承虽然有一些好处,...

  • 当心掉进Python多重继承里的坑

    关于类的知识点里面,有一块是关于多重继承,跟其他主流语言一样,Python也支持多重继承,多重继承虽然有一些好处,...

  • 35-python中多重继承

    除了从一个父类继承外,Python允许从多个父类继承,称为多重继承。 多重继承的继承链就不是一棵树了,它像这样: ...

  • python学习日记-2016.7.21

    1.多重继承 python的多重继承可以使一个子类得到多个父类的所有功能,定义多重继承很简单,只需要在定义类时在类...

  • Python基础总结(九)(继承和多态)

    这里主要列出Python中有关继承和多态的略微特殊的知识点,常见更多继承多态问题 Python允许多重继承,使用下...

网友评论

      本文标题:python 多重继承的事

      本文链接:https://www.haomeiwen.com/subject/ltecwftx.html