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实现从一组颜色中找出与给定颜色最接近颜色的方法
Mar 19 Python
C#返回当前系统所有可用驱动器符号的方法
Apr 18 Python
浅谈python字符串方法的简单使用
Jul 18 Python
python使用fcntl模块实现程序加锁功能示例
Jun 23 Python
python3 模拟登录v2ex实例讲解
Jul 13 Python
Python实现简单的HttpServer服务器示例
Sep 25 Python
《Python学习手册》学习总结
Jan 17 Python
Python实现获取邮箱内容并解析的方法示例
Jun 16 Python
Python交互环境下实现输入代码
Jun 22 Python
TensorFlow Session会话控制&amp;Variable变量详解
Jul 30 Python
基于python的Paxos算法实现
Jul 03 Python
python实现集中式的病毒扫描功能详解
Jul 09 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
PHP中include()与require()的区别说明
2010/03/10 PHP
PHP 输出URL的快捷方式示例代码
2013/09/22 PHP
PHP抓取及分析网页的方法详解
2016/04/26 PHP
js AspxButton的客户端操作
2009/06/26 Javascript
javascript的字符串按引用复制和传递,按值来比较介绍与应用
2012/12/28 Javascript
js实现多选项切换导航菜单的方法
2015/02/06 Javascript
jquery实现网页的页面平滑滚动效果代码
2015/11/02 Javascript
jQuery设置Cookie及删除Cookie实例分析
2016/04/15 Javascript
js仿支付宝多方框输入支付密码效果
2016/09/27 Javascript
微信小程序开发之相册选择和拍照详解及实例代码
2017/02/22 Javascript
详解JS中遍历语法的比较
2017/04/07 Javascript
jQuery选择器中的特殊符号处理方法
2017/09/08 jQuery
vue项目中应用ueditor自定义上传按钮功能
2018/04/27 Javascript
vue指令只能输入正数并且只能输入一个小数点的方法
2018/06/08 Javascript
详解jQuery设置内容和属性
2019/04/11 jQuery
微信小程序实现订单倒计时
2020/11/01 Javascript
js tab栏切换代码实例解析
2019/09/03 Javascript
JS+CSS+HTML实现“代码雨”类似黑客帝国文字下落效果
2020/03/17 Javascript
Antd的Table组件嵌套Table以及选择框联动操作
2020/10/24 Javascript
[47:03]Ti4第二日主赛事败者组 LGD vs iG 2
2014/07/21 DOTA
Python实现输入二叉树的先序和中序遍历,再输出后序遍历操作示例
2018/07/27 Python
python使用opencv驱动摄像头的方法
2018/08/03 Python
Transpose 数组行列转置的限制方式
2020/02/11 Python
利用python中集合的唯一性实现去重
2020/02/11 Python
python实现一次性封装多条sql语句(begin end)
2020/06/06 Python
Python中random模块常用方法的使用教程
2020/10/04 Python
英国领先的电子、技术和办公用品购物网站:Ebuyer
2018/04/04 全球购物
Hawes & Curtis官网:英国经典品牌
2019/07/27 全球购物
普通PHP程序员笔试题
2016/01/01 面试题
商务英语专业毕业生自荐信
2013/11/05 职场文书
给面试官的感谢信
2014/02/01 职场文书
人事专员岗位职责说明书
2014/07/30 职场文书
2014年协会工作总结
2014/11/22 职场文书
父亲节寄语大全
2015/02/27 职场文书
祝福语集锦:朋友新店开业祝福语
2019/12/10 职场文书