Python语言入门6.4-类的多重继承(super()函数)
小标 2018-06-20 来源 : 阅读 744 评论 0

摘要:本文主要向大家介绍了Python语言入门,类的多重继承(super()函数),希望对大家学习Python语言入门有所帮助。

本文主要向大家介绍了Python语言入门,类的多重继承(super()函数),希望对大家学习Python语言入门有所帮助。

说到面向对象,就少不了研究面向对象的特点(继承,封装,多态)。Python中类的继承的关键是正确使用super()函数,而这恰好是我们理解最不好的地方。先看看一般类的继承的代码(关于我写的类的详解1就是这么写,现在觉得写法实在比较粗糙):

class Base:
    def __init__(self):
        print('This is Base init function')class A(Base):
    def __init__(self):
        Base.__init__(self)
        print('This is init function of A')
class B(Base):
    def __init__(self):
        Base.__init__(self)
        print('This is init function of B')
class C(A,B):
    def __init__(self):
        #super().__init__(self)
        A.__init__(self)
        B.__init__(self)
        print('This is init function of C')
 
c = C()

 

控制台输出:

This is Base init function

This is init function of A

This is Base init function

This is init function of B

This is init function of C

从打印输出来看,初始化确实也没有什么问题。只是Base()被初始化两次,并不影响其功能,只是程序员接受不了。接下来用super()函数重写该段代码:

class Base:
    def __init__(self):
        print('This is Base init function')class A(Base):
    def __init__(self):
        super().__init__()
        print('This is init function of A')
class B(Base):
    def __init__(self):
        super().__init__()
        print('This is init function of B')
class C(A,B):
    def __init__(self):
        super().__init__()
        #A.__init__(self)
        #B.__init__(self)
        print('This is init function of C')
 
c = C()

打印输出:

This is Base init function

This is init function of B

This is init function of A

This is init function of C

用super()函数重写之后,Base的初始化函数就只运行了一次。 
要理解为什么会这样,我们得先去理解python是如何实现类的继承的。针对于每一个定义的类,python都会计算出一个方法解析顺序(MRO)的列表。MRO列表只是简单地对所有的基类进行线性排列:

print(C.__mro__)
print(type(C.__mro__))
 
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>)
<class 'tuple'>

可以看出,MRO是以元组的结构来储存的,同时,要实现继承,python从MRO最左边的类开始(子类),从左到右依次查找,直到查找到待查的属性为止。 
MRO列表是如何确定的呢,python采用的是C3线性化处理(C3 linearization)的技术。简单来说就是一种针对父类的归并排序它满足3个条件:

(1)先检查子类,再检查父类 
(2)有多个父类(多重继承),按照MRO列表的顺序依次检查 
(3)如果下一个类中出现两个合法的选择,那么就从第一个父类中选择(避免重复继承,保证每个父类只继承一次)

当使用super()函数时,python会继续从MRO中的下一个类开始搜索,只要每一个重新定义过的方法(比如init())都使用了super()函数,并且调用了他们一次,那么控制流最终就可以遍历整个MRO列表,并且让每个方法都只被调用一次(这就是第二个例子中为什么Base.init()只被调用一次的原因)。 
关于super()函数,还有一个很神奇的功能:它并不是一定要关联到某个类的直接父类上,甚至可以在没有直接父类的类上使用它。例如:

class A:
    def __init__(self):
        print('This is init function of A')
class B:
    def __init__(self):
        print('This is init function of B')
        super().__init__()
class C(B,A):
    pass
 
c = C()

 

打印输出:

This is init function of B

This is init function of A

那么问题来了,A并不是B的父类,但是B中使用super函数仍然可以调用A中的init()。这个就可以利用C的MRO列表来解释:

(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

B中使用了super()它就会遍历MRO,寻找下一个方法,在A中找到了,所以就调用了它。 
这就说明,在使用super()函数时可能会产生我们并不想要的结果,所以我们要遵守一些基本规则来避免这些情况的发生。例如:确保在继承体系中所有同名的方法都有可兼容的调用签名(参数数量相同,参数名称也相同,则只会调用一个)

以上就介绍了Python的相关知识,希望对Python有兴趣的朋友有所帮助。了解更多内容,请关注职坐标编程语言Python频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程