多继承以及MRO顺序
Python中的多继承问题:子类如何调用被重写的父类方法
以下的例子都是根据这个继承图来的
方式1.父类名.方法名(self,参数)
class Parent(object):
def __init__(self,house):
print("parent的init开始被调用")
self.house = house
print("parent的init结束被调用")
class Son1(Parent):
def __init__(self,house,car1):
print("son1的init开始被调用")
self.car1 = car1
Parent.__init__(self,house) # 调用父类的被重写的方法
print("son1的init结束被调用")
class Son2(Parent):
def __init__(self,house,car2):
print("son2的init开始被调用")
self.car2 = car2
Parent.__init__(self,house) # 调用父类的被重写的方法
print("son2的init结束被调用")
class Grandson(Son1,Son2):
def __init__(self,house,car1,car2):
print("grandson的init开始被调用")
Son1.__init__(self,house,car1) # 调用父类的被重写的方法
Son2.__init__(self,house,car2) # 调用父类的被重写的方法
print("grandson的init结束被调用")、
print("孙子的房子", gs.house) # 孙子的房子 别墅
print("孙子的车子1", gs.car1) # 孙子的车子1 大奔
print("孙子的车子2", gs.car2) # 孙子的车子2 大众
调用顺序:
"""
grandson的init开始被调用
son1的init开始被调用
parent的init开始被调用
parent的init结束被调用
son1的init结束被调用
son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
son2的init结束被调用
grandson的init结束被调用
"""
总结1:
该方式的好处:简洁明了,写了哪个父类名就去调用该父类的方法
导致问题:会造成父类的方法重复调用
方式2.super().方法名(参数)
class Parent(object):
def __init__(self,house,*args,**kwargs):
print("parent的init开始被调用")
self.house = house
print("parent的init结束被调用")
class Son1(Parent):
def __init__(self,car1,house,*args,**kwargs):
print("son1的init开始被调用")
self.car1 = car1
super().__init__(house,*args,**kwargs)
print("son1的init结束被调用")
class Son2(Parent):
def __init__(self,house,car2,*args,**kwargs):
print("son2的init开始被调用")
self.car2 = car2
super().__init__(house)
print("son2的init结束被调用")
class Grandson(Son1,Son2):
def __init__(self,house,car1,car2):
print("grandson的init开始被调用")
super().__init__(house,car1,car2)
print("grandson的init结束被调用")
使用super()的调用顺序是利用类里面的类.__mro__属性来查看下一个调用的顺序的,通过打印该属性,可以看到一个元组,如下
print(Grandson.__mro__) # 保证每个类只执行一次
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
调用过程:当我们实例化一个Grandson类的对象时,会执行Grandson类下面的init方法,然后我们拿着当前的类名Grandson去找mro返回的元组中Grandson类名的下一位是谁,接下来便调用谁,而不是简单的看Grandson继承的顺序,故可以判断出super()将要调用的类是Son1,然后再Son1类后面是Son2类,接下来才是父类Parent,下面是具体的调用顺序
"""
grandson的init开始被调用
son1的init开始被调用
son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
son2的init结束被调用
son1的init结束被调用
grandson的init结束被调用
"""
方式3:super(类名,self).方法(参数)
使用方法如下:
super(Son2,self).__init__(house,car1,car2)
与上个方法的区别
方式2的super里面未指定类名,故拿着super()所在的类名去mro的返回的元组中去找下一位,然后调用
而方式3由于指定了类名,故拿着指定的类名取mro返回的元组中去找下一位,然后调用
总结2
# 方式1
Son2.__init__(self, house, car2)
# 方式2
super(Son2, self).__init__(house, car1, car2)
# 方式3
super(Son2,self).__init__(house,car1,car2)
方式1直接用父类名的方法,造成父类方法的多次执行
super() 可以任意调用你要指定的父类,因此也是多继承时必须要全部传参的原因,父类只会被调用一次