• 多继承以及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方法,只需写一句话便执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因
  • 相关阅读:
    C#简单操作XML文件的增、删、改、查
    一个感觉还算可以的验证码生成程序
    安装aclocal1报错问题
    php中soap 的使用实例无需手写WSDL文件,提供自动生成WSDL文件类
    ofstream和ifstream详细用法[转]
    [原]C++ Soap客户端实例
    PHP中文件读、写、删的操作
    C++ Boost Thread 编程指南
    (转)虚函数和纯虚函数区别
    strcpy和memcpy的区别
  • 原文地址:https://www.cnblogs.com/yifengs/p/11345754.html
Copyright © 2020-2023  润新知