Python编程中对super函数的正确理解和用法解析


Posted in Python onJuly 02, 2016

当在子类需要调用父类的方法时,在python2.2之前,直接用类名调用类的方法,即非绑定的类方法,并把自身对象self作参数传进去。

class A(object): 
  def say(self): 
    print 'I am A' 
 
class B(A): 
  def say(self): 
    print 'I am B' 
    A.say(self) 
 
b = B() 
b.say()

输出

I am B
I am A

这样运作挺好,不过有个问题,当父类改了名字时,就要把这些显式调用父类的一个个更正,子类和父类耦合比较高。
于是python2.2后就推出了super()函数来避免硬编码,不用关心父类名叫什么。
使用super()函数,上面的代码可以写成如下。

class B(A): 
  def say(self): 
    print 'I am B' 
    super(B,self).say()

python3.0后,又做了改良,super()函数不用传参数,即上面的那行代码直接super().say()就行了。

需要注意的问题:

  • super只能用在新式类中。
  • super在多重继承有问题,如果子类继承多个父类,那么super调用第一个父类的方法。
  • 不要混用这两种调用父类方法的方案,要么都用非绑定的类方法,要么都用super。不然可能导致没被调用或者被调用多次。

BUT:
不要一说到 super 就想到父类!super 指的是 MRO 中的下一个类!
一说到 super 就想到父类这是初学者很容易犯的一个错误,也是我当年犯的错误。

def super(cls, inst):
  mro = inst.__class__.mro()
  return mro[mro.index(cls) + 1]

两个参数 cls 和 inst 分别做了两件事:
1. inst 负责生成 MRO 的 list
2. 通过 cls 定位当前 MRO 中的 index, 并返回 mro[index + 1]
这两件事才是 super 的实质,一定要记住!
MRO 全称 Method Resolution Order,它代表了类继承的顺序。

举个例子:

class Root(object):
  def __init__(self):
    print("this is Root")

class B(Root):
  def __init__(self):
    print("enter B")
    # print(self) # this will print <__main__.D object at 0x...>
    super(B, self).__init__()
    print("leave B")

class C(Root):
  def __init__(self):
    print("enter C")
    super(C, self).__init__()
    print("leave C")

class D(B, C):
  pass

d = D()
print(d.__class__.__mro__)

输出

enter B
enter C
this is Root
leave C
leave B
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Root'>, <type 'object'>)

知道了 super 和父类其实没有实质关联之后,我们就不难理解为什么 enter B 下一句是 enter C 而不是 this is Root(如果认为 super 代表“调用父类的方法”,会想当然的认为下一句应该是this is Root)。流程如下,在 B 的 __init__ 函数中:

super(B, self).__init__()

首先,我们获取 self.__class__.__mro__,注意这里的 self 是 D 的 instance 而不是 B 的

(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Root'>, <type 'object'>)

然后,通过 B 来定位 MRO 中的 index,并找到下一个。显然 B 的下一个是 C。于是,我们调用 C 的 __init__,打出 enter C。

顺便说一句为什么 B 的 __init__ 会被调用:因为 D 没有定义 __init__,所以会在 MRO 中找下一个类,去查看它有没有定义 __init__,也就是去调用 B 的 __init__。

其实这一切逻辑还是很清晰的,关键是理解 super 到底做了什么。

Python 相关文章推荐
Python struct.unpack
Sep 06 Python
python分割和拼接字符串
Nov 01 Python
python映射列表实例分析
Jan 26 Python
在Python中使用next()方法操作文件的教程
May 24 Python
Python中py文件引用另一个py文件变量的方法
Apr 29 Python
Python实现对特定列表进行从小到大排序操作示例
Feb 11 Python
在PYQT5中QscrollArea(滚动条)的使用方法
Jun 14 Python
详解利用OpenCV提取图像中的矩形区域(PPT屏幕等)
Jul 01 Python
Python面向对象之Web静态服务器
Sep 03 Python
Python下应用opencv 实现人脸检测功能
Oct 24 Python
Python Scrapy图片爬取原理及代码实例
Jun 12 Python
Python批量删除mysql中千万级大量数据的脚本分享
Dec 03 Python
Python中的复制操作及copy模块中的浅拷贝与深拷贝方法
Jul 02 #Python
快速排序的算法思想及Python版快速排序的实现示例
Jul 02 #Python
Python使用functools模块中的partial函数生成偏函数
Jul 02 #Python
Python之父谈Python的未来形式
Jul 01 #Python
举例讲解Python的lambda语句声明匿名函数的用法
Jul 01 #Python
Python内置数据结构与操作符的练习题集锦
Jul 01 #Python
Python设置默认编码为utf8的方法
Jul 01 #Python
You might like
web方式ftp
2006/10/09 PHP
php类常量用法实例分析
2015/07/09 PHP
yii2 数据库读写分离配置示例
2017/02/10 PHP
模仿jQuery each函数的链式调用
2009/07/22 Javascript
JavaScript中Number.MIN_VALUE属性的使用示例
2015/06/04 Javascript
jQuery form插件之formDdata参数校验表单及验证后提交
2016/01/23 Javascript
angularjs过滤器--filter与ng-repeat配合有奇效
2017/04/20 Javascript
ES6新特性三: Generator(生成器)函数详解
2017/04/21 Javascript
jQuery超简单遮罩层实现方法示例
2018/09/06 jQuery
vue路由守卫+登录态管理实例分析
2019/05/21 Javascript
JavaScript实现随机点名器
2020/03/25 Javascript
JS使用for in有序获取对象数据
2020/05/19 Javascript
vue 实现图片懒加载功能
2020/12/31 Vue.js
Python和Perl绘制中国北京跑步地图的方法
2016/03/03 Python
Python实现字符串格式化输出的方法详解
2017/09/20 Python
python实现媒体播放器功能
2018/02/11 Python
Python将string转换到float的实例方法
2019/07/29 Python
python 实现将Numpy数组保存为图像
2020/01/09 Python
Pycharm中Python环境配置常见问题解析
2020/01/16 Python
python画图常规设置方式
2020/03/05 Python
opencv 图像加法与图像融合的实现代码
2020/07/08 Python
Django+Uwsgi+Nginx如何实现生产环境部署
2020/07/31 Python
详解python 支持向量机(SVM)算法
2020/09/18 Python
python 读取、写入txt文件的示例
2020/09/27 Python
Django数据库迁移常见使用方法
2020/11/12 Python
Django用户认证系统如何实现自定义
2020/11/12 Python
10分钟理解CSS3 Grid布局
2018/12/20 HTML / CSS
欧舒丹美国官网:L’Occitane美国
2018/02/23 全球购物
初中生学习生活的自我评价
2013/11/20 职场文书
大学生怎样进行自我评价
2013/12/07 职场文书
18岁生日感言
2014/01/12 职场文书
农民工创业典型事迹
2014/01/25 职场文书
工程招投标邀请书
2014/01/30 职场文书
学习十八大宣传标语
2014/10/09 职场文书
2014年资料员工作总结
2014/11/18 职场文书
2014年妇委会工作总结
2014/12/10 职场文书