Python面向对象微案例_钻石问题与super

Posted ShenLiang2025

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python面向对象微案例_钻石问题与super相关的知识,希望对你有一定的参考价值。

Python面向对象微案例_钻石问题与super

钻石问题

子类继承多个父类且在子类里调用在父类及基类里都重写的方法时的执行会出现基类被调用多次(两次及以上)。因为子类及父类、基类的继承关系形如钻石,因此该问题又称之为钻石问题。

 

class Base:
    nums=0;
    def printInfo(self):
        print("基类里的打印方法")
        self.nums+=1 #类变量自增
class Left(Base):
    nums_left = 0;
    def printInfo(self):
        Base.printInfo(self)
        print("继承自基类左子类的打印方法")
        self.nums_left+=1
class Right(Base):
    nums_right = 0;
    def printInfo(self):
        Base.printInfo(self)
        print("继承自基类右子类的打印方法")
        self.nums_right+=1
class Sub(Left,Right):
    nums_sub=0;
    def printInfo(self):
        Left.printInfo(self)
        Right.printInfo(self)
        print("继承左类、右类的打印方法")
        self.nums_sub+=1

if __name__ == '__main__':
    print("子类继承多个父类且引用父类的调用时的执行情况:")
    s = Sub()
    s.printInfo()
    print("**********方法在各父类的调用次数**********")
    print("子类调用次数:"+str(s.nums_sub),
          "左父类调用次数:"+str(s.nums_left),
          "右父类调用次数:"+str(s.nums_right),
          "基类调用次数:"+str(s.nums))
    #查看MRO顺序
    print(s.__class__.mro())
		
'''
#执行结果
执行情况:
基类里的打印方法
继承自基类左子类的打印方法
基类里的打印方法
继承自基类右子类的打印方法
继承左类、右类的打印方法
[<class '__main__.Sub'>, <class '__main__.Left'>, <class '__main__.Right'>, <class '__main__.Base'>, <class 'object'>]
**********方法在各父类的调用次数**********
子类调用次数:1 左父类调用次数:1 右父类调用次数:1 基类调用次数:2

由此可见基类即Base类的printInfo被调用了2次。
'''

super及MRO

MRO全称为Method Resolution Order方法解析顺序,对于某个对象可以通过对象. __class__.mro()查看其继承顺序。Python对象的继承顺序是自左到右。

super()关键字像是调用父类的,但它并不是调用对应自己的父类而是调用MRO里的“父类”,及方法解析顺序里的下一个(next)对象。

class Base:
    nums=0;
    def printInfo(self):
        print("基类里的打印方法")
        self.nums+=1 #类变量自增
class Left(Base):
    nums_left = 0;
    def printInfo(self):
        super().printInfo()
        print("继承自基类左子类的打印方法")
        self.nums_left+=1
class Right(Base):
    nums_right = 0;
    def printInfo(self):
        super().printInfo()
        print("继承自基类右子类的打印方法")
        self.nums_right+=1
class Sub(Left,Right):
    nums_sub=0;
    def printInfo(self):
        super().printInfo()
        print("继承左类、右类的打印方法")
        self.nums_sub+=1

if __name__ == '__main__':
    print("子类继承多个父类且引用父类的调用时的执行情况:")
    s = Sub()
    s.printInfo()
    print("**********方法在各父类的调用次数**********")
    print("子类调用次数:"+str(s.nums_sub),
          "左父类调用次数:"+str(s.nums_left),
          "右父类调用次数:"+str(s.nums_right),
          "基类调用次数:"+str(s.nums))
    #查看MRO顺序
    print(s.__class__.mro())

'''
#执行结果
子类继承多个父类且引用父类的调用时的执行情况:
基类里的打印方法
继承自基类右子类的打印方法
继承自基类左子类的打印方法
继承左类、右类的打印方法
**********方法在各父类的调用次数**********
子类调用次数:1 左父类调用次数:1 右父类调用次数:1 基类调用次数:1
[<class '__main__.Sub'>, <class '__main__.Left'>, <class '__main__.Right'>, <class '__main__.Base'>, <class 'object'>]
'''

#由结果不难看出基类的方法被调用了一次,以下详细解释下具体的执行过程:

#Step1:当子对象s调用super().printInfo()方法时会首先到Left里找,因为s的继承顺序是Left在前,Right在后。

#Step2:在Left对象里找到printInfo()后发现里边也调用super().printInfo(),这时不是去找Left的父类即Base里的printInfo()而是去找子对象继承的下一个对象(next方法)即Right对象。

#Step3:在Right对象里找到printInfo()后发现里边也调用super().printInfo(),这时只能去找Right的父类即Base里的printInfo()而此时Base里的printInfo()即打印一串信息,至此整个链路里真正的第一个printInfo()找到,所以super().printInfo()下是先执行父类的,再执行右父类,再执行左父类,再执行子类的,即执行结果为:

基类里的打印方法

继承自基类右子类的打印方法

继承自基类左子类的打印方法

继承左类、右类的打印方法

以上是关于Python面向对象微案例_钻石问题与super的主要内容,如果未能解决你的问题,请参考以下文章

Python面向对象微案例_钻石问题与super

python 面向对象十一 super函数

python 面向对象十一 super函数

面向对象super内置函数(转)

python 中面向对象编程的几个概念

面向对象中super的作用