python里 super类的工作原理详解


Posted in Python onJune 19, 2019

super 的工作原理如下:

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

其中,cls 代表类,inst 代表实例,上面的代码做了两件事:

  1. 获取 inst 的 MRO 列表
  2. 查找 cls 在当前 MRO 列表中的 index, 并返回它的下一个类,即 mro[index + 1]

当你使用 super(cls, inst) 时,Python 会在 inst 的 MRO 列表上搜索 cls 的下一个类。

下面看一个例子:

class A:
  def __init__(self):
    self.n = 2

  def add(self, m):
    print('\n\nself is {0} @A.add'.format(self))
    self.n += m


class B(A):
  def __init__(self):
    self.n = 3

  def add(self, m):
    print('\n\nself is {0} @B.add'.format(self))
    super(B, self).add(m)
    self.n += 3


class C(A):
  def __init__(self):
    self.n = 4

  def add(self, m):
    print('\n\nself is {0} @C.add'.format(self))
    super(C, self).add(m)
    self.n += 4


class D(B, C):
  def __init__(self):
    self.n = 5

  def add(self, m):
    print('\n\nself is {0} @D.add'.format(self))

    print(super(D, self).__self__)
    print(super(D, self).__thisclass__)

    super(D, self).add(m)
    self.n += 5


if __name__ == '__main__':

  print(D.mro())
  d = D()
  d.add(2) # 等于是: D.add(d, 2)
  print(d.n)

结果是:

[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

<__main__.D object at 0x101ef16d8>


self is <__main__.D object at 0x101ef16d8> @D.add
<__main__.D object at 0x101ef16d8>
<class '__main__.D'>


self is <__main__.D object at 0x101ef16d8> @B.add


self is <__main__.D object at 0x101ef16d8> @C.add


self is <__main__.D object at 0x101ef16d8> @A.add
19

来通过这个结果具体说几点细节:

print(D.mro()) 首先打印出 D类的 mro 列表:[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>] 。 这个非常好理解。

然后我们通过d = D()创建一个D类的实例: <__main__.D object at 0x101ef16d8>; 为了方便, 我们就把这个实例object at 0x101ef16d8 叫做 “小明” 吧

召唤d.add(2) 这个函数的时候,D类中add函数的self实际上就是这个刚被创建的小明同学object at 0x101ef16d8.

那么接下来呢,super(D, self) 就是在 object at 0x101ef16d8 的mro列表中,在小明的MRO列表中, 找到 class D(D类)的下一个 class(类), 这里也就是 class B (B类) 。

注意 mro列表里 <class '__main__.D'> 的下一个是 <class '__main__.B'>

每一个 add 函数打印的都是 self is <__main__.D object at 0x101ef16d8>, 往上追溯的过程中,无论到了哪一级,self始终都是最初创建的那个 D类的实例。

这是为什么呢?

注意看 print(super(D, self).__self__) 那一行返还的输出:<__main__.D object at 0x101ef16d8> .

哦哦?! 这他妈的不是小明吗?

也就是说, super()虽然找到的是B类,召唤的是B类的 add()函数,但它的self仍然是最开始创建的D类实例(我们的 小明同学),而且召唤add()这个函数时,仍然是把这样的一个self传给了 class B 的 add()函数。

我们的 “小明”, 就这样被一次次的往上传导到了每一级的 add() 函数中, 于是每一级打印的都是:

self is <__main__.D object at 0x101ef16d8> 或者说: self is 小明

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
实例讲解Python中的私有属性
Aug 21 Python
Python的SQLAlchemy框架使用入门
Apr 29 Python
探究python中open函数的使用
Mar 01 Python
浅谈Python中的zip()与*zip()函数详解
Feb 24 Python
使用python实现mqtt的发布和订阅
May 05 Python
如何安装并使用conda指令管理python环境
Jul 10 Python
利用keras加载训练好的.H5文件,并实现预测图片
Jan 24 Python
Python3打包exe代码2种方法实例解析
Feb 17 Python
Python连接SQLite数据库并进行增册改查操作方法详解
Feb 18 Python
Python自定义聚合函数merge与transform区别详解
May 26 Python
如何用python反转图片,视频
Apr 24 Python
Python中np.random.randint()参数详解及用法实例
Sep 23 Python
Python创建或生成列表的操作方法
Jun 19 #Python
Django REST framework 分页的实现代码
Jun 19 #Python
python获取磁盘号下盘符步骤详解
Jun 19 #Python
对PyQt5基本窗口控件 QMainWindow的使用详解
Jun 19 #Python
PyQt5 多窗口连接实例
Jun 19 #Python
django框架实现一次性上传多个文件功能示例【批量上传】
Jun 19 #Python
pyqt5对用qt designer设计的窗体实现弹出子窗口的示例
Jun 19 #Python
You might like
PHP __autoload函数(自动载入类文件)的使用方法
2012/02/04 PHP
php数字运算验证码的实现代码
2015/07/30 PHP
php中array_slice和array_splice函数解析
2016/10/18 PHP
JQuery 学习笔记 选择器之一
2009/07/23 Javascript
电子商务网站上的常用的js放大镜效果
2011/12/08 Javascript
javascript-简单的日历实现及Date对象语法介绍(附图)
2013/05/30 Javascript
jquery中获得元素尺寸和坐标的方法整理
2014/05/18 Javascript
jquery实现网页的页面平滑滚动效果代码
2015/11/02 Javascript
使用jQuery mobile库检测url绝对地址和相对地址的方法
2015/12/04 Javascript
JavaScript简单获取页面图片原始尺寸的方法
2016/06/21 Javascript
详解Angular.js的$q.defer()服务异步处理
2016/11/06 Javascript
微信小程序 this和that详解及简单实例
2017/02/13 Javascript
详解vue2父组件传递props异步数据到子组件的问题
2017/06/29 Javascript
温故知新——JavaScript中的字符串连接问题最全总结(推荐)
2017/08/21 Javascript
jQuery实现鼠标响应式透明度渐变动画效果示例
2018/02/13 jQuery
Vue 解决路由过渡动画抖动问题(实例详解)
2020/01/05 Javascript
vue-openlayers实现地图坐标弹框效果
2020/09/24 Javascript
ajax jquery实现页面某一个div的刷新效果
2021/03/04 jQuery
python的tkinter布局之简单的聊天窗口实现方法
2014/09/03 Python
Python手机号码归属地查询代码
2016/05/04 Python
python使用正则表达式的search()函数实现指定位置搜索功能
2017/11/10 Python
Python数据分析之双色球统计两个红和蓝球哪组合比例高的方法
2018/02/03 Python
查看Django和flask版本的方法
2018/05/14 Python
tensorflow实现简单逻辑回归
2018/09/07 Python
浅谈Python的list中的选取范围
2018/11/12 Python
深入浅析python3中的unicode和bytes问题
2019/07/03 Python
python 自定义装饰器实例详解
2019/07/20 Python
python实现异常信息堆栈输出到日志文件
2019/12/26 Python
QML实现钟表效果
2020/06/02 Python
前端canvas动画如何转成mp4视频的方法
2019/06/17 HTML / CSS
小学生家长评语集锦
2014/01/30 职场文书
酒店营销策划方案
2014/02/07 职场文书
法制宣传实施方案
2014/03/13 职场文书
高中军训的心得体会
2014/09/01 职场文书
法定代表人授权委托书
2014/09/19 职场文书
个人党性锻炼总结
2015/03/05 职场文书