多继承以及MRO顺序

 1 class A:
 2     def test(self):
 3         print("A --- test方法")
 4 
 5     def demo(self):
 6         print("A --- demo方法")
 7 
 8 class B:
 9     def test(self):
10         print("B --- test方法")
11 
12     def demo(self):
13         print("B --- demo方法")
14 
15 
16 class C(A,B):
17     pass
18 
19 
20 c = C()
21 print(dir(c)) #dir()显示该类中所有的方法和属性
22 c.test()
23 c.demo()
24 print(C.__mro__)  #向上查询顺序
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'demo', 'test']
A --- test方法
A --- demo方法
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

  

单个调用父类的方法:

 1 # coding=utf-8
 2 
 3 print("******多继承使用类名.__init__ 发生的状态******")
 4 class Parent(object):
 5     def __init__(self, name):
 6         print('parent的init开始被调用')
 7         self.name = name
 8         print('parent的init结束被调用')
 9 
10 class Son1(Parent):
11     def __init__(self, name, age):
12         print('Son1的init开始被调用')
13         self.age = age
14         Parent.__init__(self, name)
15         print('Son1的init结束被调用')
16 
17 class Son2(Parent):
18     def __init__(self, name, gender):
19         print('Son2的init开始被调用')
20         self.gender = gender
21         Parent.__init__(self, name)
22         print('Son2的init结束被调用')
23 
24 class Grandson(Son1, Son2):
25     def __init__(self, name, age, gender):
26         print('Grandson的init开始被调用')
27         Son1.__init__(self, name, age)  # 单独调用父类的初始化方法
28         Son2.__init__(self, name, gender)
29         print('Grandson的init结束被调用')
30 
31 gs = Grandson('grandson', 12, '')
32 print('姓名:', gs.name)
33 print('年龄:', gs.age)
34 print('性别:', gs.gender)
35 
36 print("******多继承使用类名.__init__ 发生的状态******

")

结果:

******多继承使用类名.__init__ 发生的状态******
Grandson的init开始被调用
Son1的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son1的init结束被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
******多继承使用类名.__init__ 发生的状态******

  

父类会被多次调用,浪费大量的资源

MRO和super()用法:

 1 print("******多继承使用super().__init__ 发生的状态******")
 2 class Parent(object):
 3     def __init__(self, name, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数
 4         print('parent的init开始被调用')
 5         self.name = name
 6         print('parent的init结束被调用')
 7 
 8 class Son1(Parent):
 9     def __init__(self, name, age, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数
10         print('Son1的init开始被调用')
11         self.age = age
12         super().__init__(name, *args, **kwargs)  # 为避免多继承报错,使用不定长参数,接受参数
13         print('Son1的init结束被调用')
14 
15 class Son2(Parent):
16     def __init__(self, name, gender, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数
17         print('Son2的init开始被调用')
18         self.gender = gender
19         super().__init__(name, *args, **kwargs)  # 为避免多继承报错,使用不定长参数,接受参数
20         print('Son2的init结束被调用')
21 
22 class Grandson(Son1, Son2):
23     def __init__(self, name, age, gender):
24         print('Grandson的init开始被调用')
25         # 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍
26         # 而super只用一句话,执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因 super根据C3算法,每个类只调用一遍
27         # super(Grandson, self).__init__(name, age, gender) Grandson可以换成Son1或者其他,即 可以跳到指定的位置向上查询
28         super().__init__(name, age, gender)  # 默认从Grandson开始查找MRO向上顺序
29         print('Grandson的init结束被调用')
30 
31 print(Grandson.__mro__)
32 
33 gs = Grandson('grandson', 12, '')
34 print('姓名:', gs.name)
35 print('年龄:', gs.age)
36 print('性别:', gs.gender)
37 print("******多继承使用super().__init__ 发生的状态******

")

运行结果:

******多继承使用super().__init__ 发生的状态******
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandson的init开始被调用
Son1的init开始被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Son1的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
******多继承使用super().__init__ 发生的状态******

  

super总结:

1 super().__init__相对于类名.__init__,在单继承上用法基本无差
2 但在多继承上有区别,super方法能保证每个父类的方法只会执行一次,而使用类名的方法会导致方法被执行多次,具体看前面的输出结果
3 多继承时,使用super方法,对父类的传参数,应该是由于python中super的算法导致的原因,必须把参数全部传递,否则会报错
4 单继承时,使用super方法,则不能全部传递,只能传父类方法所需的参数,否则会报错
5 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍, 而使用super方法,只需写一句话便执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因
原文地址:https://www.cnblogs.com/yifengs/p/11345754.html