来自https://blog.csdn.net/sunwukong_hadoop/article/details/80175292

1、Python的继承以及调用父类成员

python子类调用父类成员有2种方法,分别是普通方法和super方法。

假设Base是基类。

class Base(object):
  def __init__(self):
    print “Base init”

普通方法:

class Leaf(Base):
def __init__(self):
Base.__init__(self)
print “Leaf init”

super方法:

class Leaf(Base):
def __init__(self):
super(Leaf, self).__init__()
print “Leaf init”

在上面简单的场景下,两个效果是一样的:

>>> leaf = Leaf()

Base init

Leaf init

2、钻石继承遇到的难题

普通方法:

class Base(object):
def __init__(self):
print “Base init” class Medium1(Base):
def __init__(self):
Base.__init__(self)
print “Medium1 init” class Medium2(Base):
def __init__(self):
Base.__init__(self)
print “Medium2 init” class Leaf(Medium1, Medium2):
def __init__(self):
Medium1.__init__(self)
Medium2.__init__(self)
print “Leaf init”

当我们生成Leaf对象时,结果如下:

>>> leaf = Leaf()

Base init

Medium1 init

Base init

Medium2 init

Leaf init

可以看到Base被初始化了两次!这是由于Medium1和Medium2各自调用了Base的初始化函数导致的。

super方法:

class Base(object):
def __init__(self):
print “Base init” class Medium1(Base):
def __init__(self):
super(Medium1, self).__init__()
print “Medium1 init” class Medium2(Base):
def __init__(self):
super(Medium2, self).__init__()
print “Medium2 init” class Leaf(Medium1, Medium2):
def __init__(self):
super(Leaf, self).__init__()
print “Leaf init”

我们生成Leaf对象:

>>> leaf = Leaf()

Base init

Medium2 init

Medium1 init

Leaf init

可以看到整个初始化过程符合我们的预期,Base只被初始化了1次。而且重要的是,相比原来的普通写法,super方法并没有写额外的代码,也没有引入额外的概念

4.   super的内核:mro

要理解super的原理,就要先了解mro。mro是method resolution order的缩写,表示了类继承体系中的成员解析顺序。

在python中,每个类都有一个mro的类方法。我们来看一下钻石继承中,Leaf类的mro是什么样子的:

>>> Leaf.mro()

[<class '__main__.Leaf'>, <class '__main__.Medium1'>, <class '__main__.Medium2'>, <class '__main__.Base'>, <type 'object'>]

可以看到mro方法返回的是一个祖先类的列表。Leaf的每个祖先都在其中出现一次,这也是super在父类中查找成员的顺序。

通过mro,python巧妙地将多继承的图结构,转变为list的顺序结构。super在继承体系中向上的查找过程,变成了在mro中向右的线性查找过程,任何类都只会被处理一次。

通过这个方法,python解决了多继承中的2大难题:

1. 查找顺序问题。从Leaf的mro顺序可以看出,如果Leaf类通过super来访问父类成员,那么Medium1的成员会在Medium2之前被首先访问到。如果Medium1和Medium2都没有找到,最后再到Base中查找。

2. 钻石继承的多次初始化问题。在mro的list中,Base类只出现了一次。事实上任何类都只会在mro list中出现一次。这就确保了super向上调用的过程中,任何祖先类的方法都只会被执行一次。

至于mro的生成算法,可以参考这篇wiki:https://en.wikipedia.org/wiki/C3_linearization

5.   super的具体用法

5.1. super(type, obj)

当我们在Leaf的__init__中写这样的super时:

  1.  
    class Leaf(Medium1, Medium2):
  2.  
    def __init__(self):
  3.  
    super(Leaf, self).__init__()
  4.  
    print “Leaf init”

super(Leaf, self).__init__()的意思是说:

  1. 获取self所属类的mro, 也就是[Leaf, Medium1, Medium2, Base]
  2. 从mro中Leaf右边的一个类开始,依次寻找__init__函数。这里是从Medium1开始寻找
  3. 一旦找到,就把找到的__init__函数绑定到self对象,并返回

从这个执行流程可以看到,如果我们不想调用Medium1的__init__,而想要调用Medium2的__init__,那么super应该写成:super(Medium1, self)__init__()

5.2. super(type, type2)

当我们在Leaf中写类方法的super时:

class Leaf(Medium1, Medium2):
def __new__(cls):
obj = super(Leaf, cls).__new__(cls)
print “Leaf new”
return obj

super(Leaf, cls).__new__(cls)的意思是说:

  1. 获取cls这个类的mro,这里也是[Leaf, Medium1, Medium2, Base]
  2. 从mro中Leaf右边的一个类开始,依次寻找__new__函数
  3. 一旦找到,就返回“非绑定”的__new__函数

由于返回的是非绑定的函数对象,因此调用时不能省略函数的第一个参数。这也是这里调用__new__时,需要传入参数cls的原因

同样的,如果我们想从某个mro的某个位置开始查找,只需要修改super的第一个参数就行

Python笔记(28)-----继承的更多相关文章

  1. Python笔记(三)继承和多态、动态语言

    一.继承 先定义一个A类 class A(object): def fun(self): print "Run A fun()" 在定义一个B类 class B(A): pass ...

  2. python笔记28(TCP,UDP,socket协议)

    今日内容 1.TCP协议 协议的特点:三次握手,四次挥手: 2.UDP协议 3.OSI七层模型:每层的物理设备,每一层协议. 4.代码部分: ①介绍socket: ②使用socket完成tcp协议的w ...

  3. python基础学习笔记—— 多继承

    本节主要内容: 1.python多继承 2.python经典类的MRO 3.python新式类的MRO.C3算法 4.super是什么鬼? 一.python多继承 在前⾯的学习过程中. 我们已经知道了 ...

  4. python基础学习笔记——单继承

    1.为什么要有类的继承性?(继承性的好处)继承性的好处:①减少了代码的冗余,提供了代码的复用性②提高了程序的扩展性 ③(类与类之间产生了联系)为多态的使用提供了前提2.类继承性的格式:单继承和多继承# ...

  5. 20.Python笔记之SqlAlchemy使用

    Date:2016-03-27 Title:20.Python笔记之SqlAlchemy使用 Tags:python Category:Python 作者:刘耀 博客:www.liuyao.me 一. ...

  6. 8.python笔记之面向对象基础

    title: 8.Python笔记之面向对象基础 date: 2016-02-21 15:10:35 tags: Python categories: Python --- 面向对象思维导图 (来自1 ...

  7. python笔记 - day8

    python笔记 - day8 参考: http://www.cnblogs.com/wupeiqi/p/4766801.html http://www.cnblogs.com/wupeiqi/art ...

  8. python笔记 - day7-1 之面向对象编程

    python笔记 - day7-1 之面向对象编程 什么时候用面向对象: 多个函数的参数相同: 当某一些函数具有相同参数时,可以使用面向对象的方式,将参数值一次性的封装到对象,以后去对象中取值即可: ...

  9. python笔记 - day7

    python笔记 - day7 参考: http://www.cnblogs.com/wupeiqi/articles/5501365.html 面向对象,初级篇: http://www.cnblog ...

  10. python笔记 - day5

    python笔记 - day5 参考: http://www.cnblogs.com/wupeiqi/articles/5484747.html http://www.cnblogs.com/alex ...

随机推荐

  1. Spring AOP 介绍与基于接口的实现

    热烈推荐:超多IT资源,尽在798资源网 声明:转载文章,为防止丢失所以做此备份. 本文来自公众号:程序之心 原文地址:https://mp.weixin.qq.com/s/vo94gVyTss0LY ...

  2. NOIP2018提高组省一冲奖班模测训练(五)

    NOIP2018提高组省一冲奖班模测训练(五) http://www.51nod.com/Contest/ContestDescription.html#!#contestId=79 今天有点浪…… ...

  3. 导入项目后下载jar包问题理解

    1.导入,然后你下载的jar包,jar下载成功,并不代表你项目里的代码就能用这个jar包了. 你必须还要本地添加进classpath.必须手动添加进类路径 2.总结就是:下载jar包是下载jar包,添 ...

  4. HDU2188(巴什博奕)

    悼念512汶川大地震遇难同胞--选拔志愿者 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...

  5. HDU 4350

    最近这些天,确实很烦恼.因为发现自己好像无论怎么样努力,也赶不上那些强校的学生.不得不承认,我们是传统弱校了.停了有一周了,什么也不想写,不停的反思,到底自己在哪里比不上人.D说,那是因为自始至终你只 ...

  6. 怎样使windows上的javaWEB项目公布到Centos上

    首先在windows上把项目导入到myeclipse或者eclipse(JEE)版本号上. 然后经过调试,没有错误后. 点击项目,然后右键导出(Export...) 然后选择JEE的war格式,这个是 ...

  7. cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第一步---開始界面&amp;关卡选择

    /* 说明: **1.本次游戏实例是<cocos2d-x游戏开发之旅>上的最后一个游戏,这里用3.0重写并做下笔记 **2.我也问过木头本人啦.他说:随便写,第一别全然照搬代码:第二能够说 ...

  8. 上机题目(中级)- 用小数形式输出指定符号出现的频率 (Java)

    题目例如以下:

  9. Linux下安装intellij idea

    1.下载 http://www.jetbrains.com/idea/download/#section=linux 我下载的是不带jdk的版本 2.放入opt目录中 3.解压到usr下面的intel ...

  10. Linux就该这么学 20181009(第十二章 SAMBA)

    参考链接https://www.linuxprobe.com Samba 跨平台的文件共享 linux-linux linux-windows /etc/samba/smb.conf 里面 []这个名 ...