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中Django框架利用url来控制登录的方法
Jul 25 Python
Python加密方法小结【md5,base64,sha1】
Jul 13 Python
对Python中的@classmethod用法详解
Apr 21 Python
python 快速把超大txt文件转存为csv的实例
Oct 26 Python
对python实现模板生成脚本的方法详解
Jan 30 Python
2019 Python最新面试题及答案16道题
Apr 11 Python
python opencv将表格图片按照表格框线分割和识别
Oct 30 Python
django实现用户注册实例讲解
Oct 30 Python
python线程信号量semaphore使用解析
Nov 30 Python
Python基于read(size)方法读取超大文件
Mar 12 Python
基于selenium及python实现下拉选项定位select
Jul 22 Python
关于Python3爬虫利器Appium的安装步骤
Jul 29 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
DIY实用性框形天线
2021/03/02 无线电
如何在PHP中使用Oracle数据库(1)
2006/10/09 PHP
Android App中DrawerLayout抽屉效果的菜单编写实例
2016/03/21 PHP
php获取字符串前几位的实例(substr返回字符串的子串用法)
2017/03/08 PHP
PHP 进程池与轮询调度算法实现多任务的示例代码
2019/11/26 PHP
javascript radio 联动效果
2009/03/04 Javascript
ExtJs扩展之GroupPropertyGrid代码
2010/03/05 Javascript
jquery keypress,keyup,onpropertychange键盘事件
2010/06/25 Javascript
jQuery UI AutoComplete 自动完成使用小记
2010/08/21 Javascript
jQuery仿Excel表格编辑功能的实现代码
2013/05/01 Javascript
JavaScript实现级联菜单的方法
2015/06/29 Javascript
总结JavaScript中布尔操作符||与&amp;&amp;的使用技巧
2015/11/17 Javascript
Jquery zTree 树控件异步加载操作
2016/02/25 Javascript
JS判断是否长按某一键的方法
2016/03/02 Javascript
用原生js统计文本行数的简单示例
2016/08/19 Javascript
Vue.js 利用v-for中的index值实现隔行变色
2018/08/01 Javascript
浅析js中mvvm模式实现的原理
2018/10/06 Javascript
如何在微信小程序中存setStorage
2019/12/13 Javascript
手把手教您实现react异步加载高阶组件
2020/04/07 Javascript
[04:09]2014DOTA2国际邀请赛Ti西雅图 历届冠军相继出局 BBC综述今日比赛
2014/07/20 DOTA
python使用PyFetion来发送短信的例子
2014/04/22 Python
在Python程序中操作文件之flush()方法的使用教程
2015/05/24 Python
Python读写ini文件的方法
2015/05/28 Python
pip 20.3 新版本发布!即将抛弃 Python 2.x(推荐)
2020/12/16 Python
韩国现代百货官网:Hmall
2018/03/21 全球购物
网上卖盒饭创业计划书范文
2014/02/07 职场文书
担保书格式及范文
2014/04/01 职场文书
领导干部群众路线教育实践活动剖析材料
2014/10/10 职场文书
审计局2014法制宣传日活动总结
2014/11/01 职场文书
毕业生评语大全
2015/01/04 职场文书
2015年党员干部承诺书
2015/01/21 职场文书
大国崛起英国观后感
2015/06/02 职场文书
电影雨中的树观后感
2015/06/15 职场文书
详解非极大值抑制算法之Python实现
2021/06/28 Python
Go本地测试解耦任务拆解及沟通详解Go本地测试的思路沟通的重要性总结
2022/06/21 Golang
全网非常详细的pytest配置文件
2022/07/15 Python