天天看点

多重继承和多继承, super, __mro__继承

继承

(父类派生子类,子类继承父类)

通过继承,可以让子类去拥有父类中的属性和方法,而不必重新编写相同的代码,并且可以在父类的基础上添加新的属性和功能。

在继承的同时,子类还可以重写父类中的方法,从而获取与父类不同的功能,实现多态。

在 Python 中 所有的类都是存在继承关系的,没有显示继承的,都是默认继承 object 类

提高开发效率,避免代码冗余

#多重单继承初始化问题

class Person(object):   
    def __init__(self, name):          # <__main__.Son object at 0x7f95c505d630>
        self.__name = name
        print("Person init")

    def get_name(self):
        print(self.__name)


class Parent(Person):
    def __init__(self, name, age):      # <__main__.Son object at 0x7f95c505d630>
        Person.__init__(self, name)
        self.__age = age
        print("Parent init")

    def get_age(self):
        print(self.__age)


class Son(Parent):
    def __init__(self, name, age, gender):
        Parent.__init__(self, name, age)
        self.__gender = gender
        print("Son init")

    def get_gender(self):
        print(self.__gender)


wo = Son('tom', 22, 'male')
wo.get_name()
wo.get_age()
wo.get_gender()

>>>Person init
Parent init
Son init
tom
22
male
           
多重继承和多继承, super, __mro__继承

当在初始化时,子类只需要初始化自己扩展的属性即可,父类中的属性交给父类去初始化。

多重多继承的初始化问题

class Person(object):
    def __init__(self, name):
        self.__name = name
        print("Person init")

    def get_name(self):
        return self.__name


class Monther(Person):
    def __init__(self, name, job):
        Person.__init__(self, name)
        self.__job = job
        print("Monther init")

    def get_job(self):
        return self.__job


class Parent(Person):
    def __init__(self, name, age):
        Person.__init__(self, name)
        self.__age = age
        print("Parent init")

    def get_age(self):
        return self.__age


class Son(Parent, Monther):
    def __init__(self, name, age, job, gender):
        Parent.__init__(self, name, age)
        Monther.__init__(self, name, job)

        self.__gender = gender
        print("Son init")

    def get_gender(self):
        return self.__gender


wo = Son('tom', 22, 'teacher', 'male')
print(wo.get_name(), wo.get_age(), wo.get_job(), wo.get_gender())

>>>Person init
Parent init
Person init
Monther init
Son init
tom 22 teacher male
           

很明显这是不对的,因为 Father 类和 Mother 类都是继承于 Person 类的,在自己的初始化方法中,执行了父类的初始化方法,所以执行了两次,造成了代码冗余

多重多继承 =》 person被调用多次 ==> object更多次

super 函数

super函数解决继承中父类被重复初始化问题

super函数的格式

super(CurrentClassName, self).init(*args, **kwargs)

class Person(object):
    def __init__(self, name):
        self.__name = name
        print("Person init")

    def get_name(self):
        return self.__name


class Mother(Person):
    def __init__(self, job, *args):
        super(Mother, self).__init__(*args)
        self.__job = job
        print("Mother init")

    def get_job(self):
        return self.__job


class Father(Person):
    def __init__(self, age, *args):
        super(Father, self).__init__(*args)
        self.__age = age
        print("Father init")

    def get_age(self):
        return self.__age


class Son(Father, Mother):
    def __init__(self, name, age, job, gender):
        super(Son, self).__init__(name, age, job)
        self.__gender = gender
        print("Son init")

    def get_gender(self):
        return self.__gender


wo = Son('tom', 22, 'teacher', 'male')
print(wo.get_name(), wo.get_age(), wo.get_job(), wo.get_gender())

>>>Person init
Mother init
Father init
Son init
teacher tom 22 male
           

通过执行结果来看,使用 super 改进后的代码只初始化了一次 Person 的初始化方法。

###钻石继承

多重继承和多继承, super, __mro__继承

##mro

mro Method Resolution Order 方法解析顺序

在类出现继承时,每个类中都会保存一个当前类的继承关系的表。

super 函数在执行时,会在自己保存的这个继承关系中去查找第一个参数,也就是当前的类名的下一个类是谁。然后去调用下个类的初始化方法。

Python 中使用广度优先算法来决定继承关系的排序

多重继承和多继承, super, __mro__继承

Mro顺序

print(Son.__mro__)

>>>(<class '__main__.Son'>, <class '__main__.Father'>, <class '__main__.Mother'>, <class '__main__.Person'>, <class 'object'>)
           

在初始化父类时,也可以使用 super().init() 函数来调用,简化super函数的写法。

这时,super函数中没有参数,还是能正确执行,就是依照 mro 中的顺序来执行的。

super().__init__(*args)
           

对象在调用方法时,也会依照这个顺序来查找方法。

类在继承时,继承关系的书写顺序会影响 mro 中的顺序。

继续阅读