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

本文详细介绍了Python中继承的基本概念,包括单继承和多继承的初始化问题,以及如何使用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

这里写图片描述
当在初始化时,子类只需要初始化自己扩展的属性即可,父类中的属性交给父类去初始化。

多重多继承的初始化问题

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 的初始化方法。

###钻石继承
这里写图片描述

##mro
mro Method Resolution Order 方法解析顺序

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

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

Python 中使用广度优先算法来决定继承关系的排序
这里写图片描述

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 中的顺序。

### Python多重继承时 `super` 函数与 MRO 的工作机制 在 Python 中,多重继承允许一个类从多个父类继承属性方法。然而,多重继承可能导致方法名冲突调用顺序不明确的问题。为了解决这些问题,Python 引入了 **方法解析顺序(MRO)** `super()` 函数来确保方法调用的一致性可预测性。 #### 1. 方法解析顺序(MROMRO 是 Python 用于确定在多继承环境中如何查找方法或属性的规则。它定义了一个线性化的类继承顺序列表,确保每个类只出现一次,并且遵循一定的优先级规则。Python 使用 **C3 线性化算法** 来计算 MRO[^1]。 例如: ```python class A: def method(self): print("A") class B(A): def method(self): print("B") class C(A): def method(self): print("C") class D(B, C): def method(self): super().method() ``` 在上述代码中,`D` 类继承自 `B` `C`。当调用 `D().method()` 时,Python 会根据 MRO 确定方法调用顺序。可以通过以下方式查看 MRO 列表: ```python print(D.mro()) ``` 输出结果为: ``` [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>] ``` 这表明 Python 会按照 `D -> B -> C -> A -> object` 的顺序查找方法[^4]。 #### 2. `super()` 函数的工作机制 `super()` 函数是 Python 提供的一个内置函数,用于调用父类的方法。它结合 MRO 工作,动态地确定下一个要调用的类[^2]。 在多重继承场景中,`super()` 并不是简单地调用直接父类的方法,而是按照 MRO 顺序调用下一个类的方法。以下是一个示例: ```python class A: def method(self): print("A") class B(A): def method(self): super().method() print("B") class C(A): def method(self): super().method() print("C") class D(B, C): def method(self): super().method() print("D") ``` 调用 `D().method()` 的输出为: ``` A C B D ``` 解释如下: 1. 调用 `D.method()`,`super().method()` 根据 MRO 调用 `B.method()`。 2. 在 `B.method()` 中,`super().method()` 根据 MRO 调用 `C.method()`。 3. 在 `C.method()` 中,`super().method()` 根据 MRO 调用 `A.method()`。 4. 最后依次打印 `A`、`C`、`B` `D`[^5]。 #### 3. 动态方法解析 `super()` 的另一个重要特性是其动态性。即使在运行时修改类的继承结构,`super()` 仍然能够正确地根据新的 MRO 找到合适的方法[^3]。 例如: ```python class A: def method(self): print("A") class B(A): def method(self): super().method() print("B") class C(A): def method(self): super().method() print("C") class D(B, C): def method(self): super().method() print("D") # 动态修改继承关系 class E(C, B): def method(self): super().method() print("E") d = D() d.method() # 输出:A C B D e = E() e.method() # 输出:A B C E ``` 在上述代码中,`E` 类的继承顺序被修改为 `(C, B)`,因此其 MRO 方法调用顺序也随之改变。 --- ### 总结 - **MRO** 是 Python 用于解决多重继承中方法解析顺序问题的关键机制,通过 C3 线性化算法生成唯一的类继承顺序列表。 - **`super()`** 函数结合 MRO 动态地调用下一个类的方法,确保方法调用的一致性可预测性[^2]。 - 在多重继承场景中,`super()` 并非简单调用直接父类的方法,而是按照 MRO 顺序调用下一个类的方法[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值