ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Python 面向对象 之 多继承 MRO

2020-01-31 18:00:42  阅读:251  来源: 互联网

标签:__ .__ name Python self am 面向对象 init MRO


关于子类的继承.

在子类初始化的时候, 是需要手动调用父类的初始化方法来说明的, 语法为: **父类名.__ init__(self, ...)**

多继承 - Bug

这里主要演示一个, 多继承会出现的问题, 其实也不算bug吧, 原理我也没有仔细去推敲过哈, 先露出来看看吧.

class 父亲:
    def __init__(self, name):
        self.name = name
        print("i am you father...")


class 长子(父亲):
    def __init__(self, name, age):
        self.age = age
        父亲.__init__(self, name)
        print(" i am eldest son")

class 次子(父亲):
    def __init__(self, name, gender):
        self.gender = gender
        父亲.__init__(self, name)
        print("i am the little son")

class 长孙(长子, 次子):
    """收养的哦"""
    def __init__(self, name, age, gender):
        长子.__init__(self, name, age)
        次子.__init__(self, name, gender)
        print("i am the sweet heart")


if __name__ == '__main__':

    king = 长孙("小王子", 23, "F")
i am you father...
i am eldest son
    
i am you father...  # 多执行了一次 ???

i am the little son
i am the sweet heart

卧槽. ....父类被执行了2次, 这感觉是浪费内存了呀, 嗯..有些紧张....

为啥会出现调用2次父类呢? 或者 如何只让调用一次就好呢 ? 分析一波上面这一段代码

长子.__init__(self, name, age) --> class 长子(父亲) --> class 父亲 -> print("father...")
次子.__init__(self, name, gender) --> class 次子(父亲) --> class 父亲 -> print("father...")

因此, 被调用了2次是没有问题的, 但这就带来一个新的优化问题: 浪费内存, 因为重复开辟空间了呀.

更一般地描述, 即在多继承的情况下, 父类的属性可能会出现被多次执行的情况, 这里仅仅是一个简单的case, 如果非常复杂的结果, 则会浪费非常多的内存和反复调用.

多继承 MRO

MRO - 引入

MRO 是 Pyhton 用来解决上面的这种, 会产生重复开辟空间的问题. 解决的办法是将 复杂结构上的所有类 全部映射到一个线性顺序上 (线性表), 这个顺序就是 MRO 顺序.

MRO表, 事先就调用好了, 按表的顺序调用, 从右到左

print(长孙.__mro__)

# output

(<class '__main__.长孙'>, <class '__main__.长子'>, <class '__main__.次子'>, <class '__main__.父亲'>, <class 'object'>)

这个线性表, 我从执行的角度来看, 就是个 , 父类在栈底, 小王子在栈顶 (Top) , 而搜索的顺序, 兄弟们, 定睛一看, 这一层, 一层第搜索,.... 感觉这就是 树的广度优先算法 呀.

MRO - super

官方已经把这个问题给解决了, 方式就是使用关键字 super

class 父亲:
    def __init__(self, name):
        self.name = name
        print("i am you father...")


class 长子(父亲):
    def __init__(self, name, age, *args):
        self.age = age
        super().__init__(name, *args)
        print(" i am eldest son")


class 次子(父亲):
    def __init__(self, name, gender):
        self.gender = gender
        super().__init__(name)
        print("i am the little son")


class 长孙(长子, 次子):
    """收养的哦"""

    def __init__(self, name, age, gender):
        super().__init__(name,  age, gender)
        print("i am the sweet heart")


if __name__ == '__main__':
    king = 长孙("小王子", 23, "F")
    print(长孙.__mro__)
i am you father...
i am the little son
i am eldest son
i am the sweet heart

(<class '__main__.长孙'>, <class '__main__.长子'>, <class '__main__.次子'>, <class '__main__.父亲'>, <class 'object'>)

小结

  • 多继承会产生重复调用的问题, 浪费内存空间
  • MRO顺序是Python将类映射到一个线性表中来调用, 有序的, 能避免重复调用, 搜索算法目测是广度优先
  • super 的理解和用法

标签:__,.__,name,Python,self,am,面向对象,init,MRO
来源: https://www.cnblogs.com/chenjieyouge/p/12246113.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有