Python 面向对象 之 多继承 MRO
Posted 宁鸣而死
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 面向对象 之 多继承 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 的理解和用法
以上是关于Python 面向对象 之 多继承 MRO的主要内容,如果未能解决你的问题,请参考以下文章