本文实例讲述了python中super函数用法。分享给大家供大家参考,具体如下:

这是个高大上的函数,在python装13手册里面介绍过多使用可显得自己是高手 23333. 但其实他还是很重要的. 简单说, super函数是调用下一个父类(超类)并返回该父类实例的方法. 这里的下一个的概念参考后面的MRO表介绍.

help介绍如下:

super(type, obj) -> bound super object; requires isinstance(obj, type)

super(type) -> unbound super object

super(type, type2) -> bound super object; requires issubclass(type2, type)

Typical use to call a cooperative superclass method:

class C(B):

def meth(self, arg):

super(C, self).meth(arg)

由此可知, super有三种用法, 第一参数总是召唤父类的那个类, 第二参数可缺(返回非绑定父类对象),也可以是实例对象或该类的子类. 最终返回的都是父类的实例(绑定或非绑定). 在Python3中,super函数多了一种用法是直接super(),相当于super(type,首参), 这个首参就是一般的传入的self实例本身啦. 因为在py2里面常用也是这种写法.

另外, 在py2中, super只支持新类( new-style class, 就是继承自object的).

为什么要调用父类?

在类继承时, 要是重定义某个方法, 这个方法就会覆盖掉父类的相应同名方法. 通过调用父类实例, 可以在子类中同时实现父类的功能.例如: # Should be new-class based on object in python2.

class A(object):

def __init__(self):

print "enter A"

print "leave A"

class B(A):

def __init__(self):

print "enter B"

super(B, self).__init__()

print "leave B"

>>> b = B()

enter B

enter A

leave A

leave B

通过调用super获得父类实例从而可以实现该实例的初始化函数. 这在实践中太常用了 (因为要继承父类的功能, 又要有新的功能).

直接使用父类来调用的差异

事实上, 上面的super函数方法还可以这么写: class A(object):

def __init__(self):

print "enter A"

print "leave A"

class B(A):

def __init__(self):

print "enter B"

A.__init__(self)

print "leave B"

通过直接使用父类类名来调用父类的方法, 实际也是可行的. 起码在上面的例子中效果上他们现在是一样的. 这种方法在老式类中也是唯一的调用父类的方法 (老式类没有super).

通过父类类名调用方法很常用, 比较直观. 但其效果和super还是有差异的. 例如: class A(object):

def __init__(self):

print "enter A"

print "leave A"

class B(A):

def __init__(self):

print "enter B"

A.__init__(self)

print "leave B"

class C(A):

def __init__(self):

print "enter C"

A.__init__(self)

print "leave C"

class D(B,C):

def __init__(self):

print "enter D"

B.__init__(self)

C.__init__(self)

print "leave D"

>>> d=D()

enter D

enter B

enter A

leave A

leave B

enter C

enter A

leave A

leave C

leave D

可以发现, 这里面A的初始化函数被执行了两次. 因为我们同时要实现B和C的初始化函数, 所以分开调用两次, 这是必然的结果.

但如果改写成super呢? class A(object):

def __init__(self):

print "enter A"

print "leave A"

class B(A):

def __init__(self):

print "enter B"

super(B,self).__init__()

print "leave B"

class C(A):

def __init__(self):

print "enter C"

super(C,self).__init__()

print "leave C"

class D(B,C):

def __init__(self):

print "enter D"

super(D,self).__init__()

print "leave D"

>>> d=D()

enter D

enter B

enter C

enter A

leave A

leave C

leave B

leave D

会发现所有父类ABC只执行了一次, 并不像之前那样执行了两次A的初始化.

然后, 又发现一个很奇怪的: 父类的执行是 BCA 的顺序并且是全进入后再统一出去. 这是MRO表问题, 后面继续讨论.

如果没有多继承, super其实和通过父类来调用方法差不多. 但, super还有个好处: 当B继承自A, 写成了A.__init__, 如果根据需要进行重构全部要改成继承自 E,那么全部都得改一次! 这样很麻烦而且容易出错! 而使用super()就不用一个一个改了(只需类定义中改一改就好了)

Anyway, 可以发现, super并不是那么简单.

MRO 表

MRO是什么? 可以通过以下方式调出来: >>> D.mro() # or d.__class__.mro() or D.__class__.mro(D)

[D, B, C, A, object]

>>> B.mro()

[B, A, object]

>>> help(D.mro)

#Docstring:

#mro() -> list

#return a type's method resolution order

#Type: method_descriptor

MRO就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表 (类继承顺序表去理解也行) 啦.

这个表有啥用? 首先了解实际super做了啥: def super(cls, inst):

mro = inst.__class__.mro()

return mro[mro.index(cls) + 1]

换而言之, super方法实际是调用了cls的在MRO表中的下一个类. 如果是简单一条线的单继承, 那就是父类->父类一个一个地下去罗. 但对于多继承, 就要遵循MRO表中的顺序了. 以上面的D的调用为例:

d的初始化

-> D (进入D) super(D,self)

-> 父类B (进入B) super(B,self)

-> 父类C (进入C) super(C,self)

-> 父父类A (进入A) (退出A) # 如有继续super(A,self) -> object (停了)

-> (退出C)

-> (退出B)

-> (退出D)

所以, 在MRO表中的超类初始化函数只执行了一次!

那么, MRO的顺序究竟是怎么定的呢? 这个可以参考官方说明The Python 2.3 Method Resolution Order . 基本就是, 计算出每个类(从父类到子类的顺序)的MRO, 再merge 成一条线. 遵循以下规则:

在 MRO 中,基类永远出现在派生类后面,如果有多个基类,基类的相对顺序保持不变。 这个原则包括两点:

1. 基类永远在派生类后面

2. 类定义时的继承顺序影响相对顺序.

如果有以下继承 (Python中的super用法详解):

object

/ \

/ A

| / \

B-1 C-2 D-2

\ / /

E-1 /

\ /

F

那么MRO是: F -> E -> B -> C -> D -> A -> object

怎么解释呢?

根据官方的方法, 是: L(O) = O

L(B) = B O

L(A) = A O

L(C) = C A O

L(D) = D A O

L(E) = E + merge(L(B),L(C))

= E + merge(BO,CAO)

= E + B + merge(O,CAO)

= E + B + C + merge(O,AO)

= E + B + C + A + merge(O,O)

= E B C A O

L(F) = F + merge(L(E),L(D))

= F + merge(EBCAO,DAO)

= F + EBC + merge(AO,DAO)

= F + EBC + D + merge(AO,AO)

= F EBC D AO

看起来很复杂..但还是遵循在 MRO 中,基类永远出现在派生类后面,如果有多个基类,基类的相对顺序保持不变。所以, 我个人认为可以这么想: 先找出最长深度最深的继承路线F->E->C->A->object. (因为必然基类永远出现在派生类后面) 类似深度优先, 定出其余顺序: F->E->B->obj, F->D->A-object 如果有多个基类,基类的相对顺序保持不变, 类似于merge时优先提前面的项. 所以排好这些路线: (FEBO, FECAO, FDAO) F->E->B->obj且E(B,C)决定B在C前面.所以F->E->B->C->A->obj(相当于F+merge(EBO,ECAO)). F->D->A-object且F(E,D)决定了D在E后, 所以D在E后A前. 因为相对顺序, 相当于FE+merge(BCAO, DAO), 所以FE BC D AO

更多可参考 Raymond Hettinger 的Python's super() considered super! (据说很经典的讨论) James Knight 的 Python's Super Considered Harmful Py3 cookbook: 8.7 调用父类方法http://python3-cookbook.readthedocs.org/zh_CN/latest/c08/p07_calling_method_on_parent_class.html Python编程中对super函数的正确理解和用法解析

关于Python相关内容感兴趣的读者可查看本站专题:《Python面向对象程序设计入门与进阶教程》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python编码操作技巧总结》及《Python入门与进阶经典教程》

希望本文所述对大家Python程序设计有所帮助。

python中的super用法详解_Python中super函数用法实例分析相关推荐

  1. python中map用法详解_Python:map函数用法详解

    一个简单的例子:将一个list中所有元素平方,常规的做法如下图所示,虽然实现了这个功能,但并没有给人一目了然的感觉.若换成map来实现,则会好很多. 常规方法 map函数 1.map函数介绍及其简单使 ...

  2. python之33个关键字详解_Python 中的关键字 with 详解

    在 Python 2.5 中,with关键字被加入.它将常用的 try ... except ... finally ...模式很方便的被复用.看一个最经典的例子: with open('file.t ...

  3. python中的super用法详解_Python中super的用法实例

    super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO).重复调用(钻石继承)等种种问题.总之前人留下的经验就是:保持一致性 ...

  4. python中if else用法详解_Python 中的 else详解

    我们都知道 Python 中else的基本用法是在条件控制语句中的 if...elif...else...,但是 else 还有两个其它的用途,一是用于循环的结尾,另一个是用在错误处理的 try 中. ...

  5. C语言return的用法详解,C语言函数返回值详解。 (本次转载仅供学习,感谢原创!!转发自C语言中文网,如有侵权请私信本人删除)

    C语言return的用法详解,C语言函数返回值详解 转载:http://c.biancheng.net/view/1855.html 函数的返回值是指函数被调用之后,执行函数体中的代码所得到的结果,这 ...

  6. python scatter参数详解_Python中scatter函数参数及用法详解

    最近开始学习Python编程,遇到scatter函数,感觉里面的参数不知道什么意思于是查资料,最后总结如下: 1.scatter函数原型 2.其中散点的形状参数marker如下: 3.其中颜色参数c如 ...

  7. python scatter参数详解_Python 中 scatter 函数参数及用法详解

    Python 中 scatter 函数参数及用法详解 Python 中 scatter 函数参数及用法详解 这里有新鲜出炉的 Python 教程, 程序狗速度看过来! Python 编程语言 Pyth ...

  8. js数组中foEach和map的用法详解 jq中的$.each和$.map

    数组中foEach和map的用法详解 相同点: 1.都是循环遍历数组(仅仅是数组)中的每一项. 2.forEach() 和 map() 里面每一次执行匿名函数都支持3个参数:数组中的当前项value, ...

  9. java中this.getclass()_详解java中this.getClass()和super.getClass()的实例

    详解java中this.getClass()和super.getClass()的实例 前言: 遇到this.getClass()和super.getClass()的返回值感到疑惑,经过探索豁然开朗. ...

最新文章

  1. 交叉表的简单实现2:使用前端程序实现
  2. Linux 64bit下Oracle11g安装手册
  3. Floats and marginpars not allowed inside `multicols' Unknown float option `H'. 基于LaTex+VSCode+MAC
  4. 求职受性别限制?数据指明2021女性求职新方向
  5. html中 一条样式规则,css规则的基本格式是什么?
  6. IP: 169.254.0.0/16 地址用途
  7. CentOS7 搭建基于DPDK的FD.io VPP环境-1
  8. 面试题32:从上到下打印二叉树
  9. Android Camera数据流分析全程记录(overlay方式一)
  10. HashMap,,ConcurrentHashMap------------------浅谈!!
  11. oracle instant client package,Oracle数据库之Oracle Instant Client的安装和使用
  12. AI2019下载Adobe Illustrator CC2019安装教程
  13. QSS实践汇总(3)——QComboBox样式(风格)
  14. 2019.02 随笔(一)
  15. 齐齐哈尔计算机应用软件学校,黑龙江齐齐哈尔计算机应用技术课程
  16. 【ERROR】ValueError: Of the four parameters: start, end, periods, and freq, exactly three must be spec
  17. python人文社科研究_人文社科论文写作数据分析利器|SPSS+Stata+Endnote+Python
  18. eclipse 解决 java.lang.NoClassDefFoundError: ilog/concert/IloException
  19. //编写一个学生类(Students),包括姓名(name)、性别(sex)、学号(num)、语文课(Chinese)、英语课(English)、 //数学课(Math)和平均值(avg)
  20. Matlab读取视频文件

热门文章

  1. java –cp_Java –缺少字体–崩溃的应用程序!
  2. 通过aws部署推荐系统_通过AWS Elastic Beanstalk轻松进行Spring Boot部署
  3. java实现可选形参_Java:可选的可选实现
  4. 2019 java值得学吗_Java认证值得吗?
  5. 您如何使用硒来计算自动化测试的投资回报率?
  6. Java中Long到Int的精确转换
  7. java 垃圾回收手动回收_Java垃圾回收(4)
  8. java集合的功能_功能性Java集合
  9. camel mq_Camel:构建基于消息的应用程序
  10. java 代码冲突检测_Java中常见的代码冲突