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 相关文章推荐
Python3.x中自定义比较函数
Apr 24 Python
Python自定义一个异常类的方法
Jun 27 Python
使用pandas实现连续数据的离散化处理方式(分箱操作)
Nov 22 Python
pytorch AvgPool2d函数使用详解
Jan 03 Python
Python中私有属性的定义方式
Mar 05 Python
Django 解决阿里云部署同步数据库报错的问题
May 14 Python
Python使用tkinter实现摇骰子小游戏功能的代码
Jul 02 Python
详解python tcp编程
Aug 24 Python
基于python实现坦克大战游戏
Oct 27 Python
python中pyplot基础图标函数整理
Nov 10 Python
如何用python 操作zookeeper
Dec 28 Python
java关于string最常出现的面试题整理
Jan 18 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
一些花式咖啡的配方
2021/03/03 冲泡冲煮
PHP中CURL的CURLOPT_POSTFIELDS参数使用细节
2014/03/17 PHP
解析PHP的Yii框架中cookie和session功能的相关操作
2016/03/17 PHP
JavaScript中this关键字使用方法详解
2007/03/08 Javascript
Javascript注入技巧
2007/06/22 Javascript
javascript 手动给表增加数据的小例子
2013/07/10 Javascript
jquery插件jTimer(jquery定时器)使用方法
2013/12/23 Javascript
jquery 构造函数在表单提交过程中修改数据
2015/05/25 Javascript
在jQuery中使用$而避免跟其它库产生冲突的方法
2015/08/13 Javascript
Java中Timer的用法详解
2015/10/21 Javascript
jquery遍历json对象集合详解
2016/05/18 Javascript
js从数组中删除指定值(不是指定位置)的元素实现代码
2016/09/13 Javascript
easyui 中的datagrid跨页勾选问题的实现方法
2017/01/18 Javascript
js canvas画布实现高斯模糊效果
2018/11/27 Javascript
jsonp实现百度下拉框功能的方法分析
2019/05/10 Javascript
countup.js实现数字动态叠加效果
2019/10/17 Javascript
js实现树形数据转成扁平数据的方法示例
2020/02/27 Javascript
pyqt和pyside开发图形化界面
2014/01/22 Python
python使用openpyxl库修改excel表格数据方法
2018/05/03 Python
python3中os.path模块下常用的用法总结【推荐】
2018/09/16 Python
Python开发网站目录扫描器的实现
2019/02/21 Python
python+openCV利用摄像头实现人员活动检测
2019/06/22 Python
python logging模块的使用总结
2019/07/09 Python
给大家整理了19个pythonic的编程习惯(小结)
2019/09/25 Python
Django restframework 框架认证、权限、限流用法示例
2019/12/21 Python
python实现一个简单RPC框架的示例
2020/10/28 Python
CSS3颜色值RGBA与渐变色使用介绍
2020/03/06 HTML / CSS
html5移动端自适应布局的实现
2020/04/15 HTML / CSS
代领毕业证委托书
2014/08/02 职场文书
教师节慰问信
2015/02/15 职场文书
2015年南京大屠杀纪念日活动总结
2015/03/24 职场文书
返乡农民工证明
2015/06/24 职场文书
堂吉诃德读书笔记
2015/06/30 职场文书
小学家庭教育心得体会
2016/01/14 职场文书
MySQL 百万级数据的4种查询优化方式
2021/06/07 MySQL
MySQL数据库事务的四大特性
2022/04/20 MySQL