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实现socket客户端和服务端简单示例
Feb 24 Python
Python输出PowerPoint(ppt)文件中全部文字信息的方法
Apr 28 Python
Python编程中的异常处理教程
Aug 21 Python
python类的继承实例详解
Mar 30 Python
Python三种遍历文件目录的方法实例代码
Jan 19 Python
解决安装tensorflow遇到无法卸载numpy 1.8.0rc1的问题
Jun 13 Python
Django 限制用户访问频率的中间件的实现
Aug 23 Python
PyQt5根据控件Id获取控件对象的方法
Jun 25 Python
Python Multiprocessing多进程 使用tqdm显示进度条的实现
Aug 13 Python
python中如何进行连乘计算
May 28 Python
学python最电脑配置有要求么
Jul 05 Python
python下载的库包存放路径
Jul 27 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
使用XDebug调试及单元测试覆盖率分析
2011/01/27 PHP
PHP从FLV文件获取视频预览图的方法
2015/03/12 PHP
浅谈php中urlencode与rawurlencode的区别
2016/09/05 PHP
Javascript &amp; DHTML 实例编程(教程)(三)初级实例篇1—上传文件控件实例
2007/06/02 Javascript
使用Jquery来实现可以输入值的下拉选单 雏型
2011/12/06 Javascript
JavaScript图片放大技术(放大镜)实现代码分享
2013/11/14 Javascript
JavaScript实现找出数组中最长的连续数字序列
2014/09/03 Javascript
js的toUpperCase方法用法实例
2015/01/27 Javascript
jQuery+slidereveal实现的面板滑动侧边展出效果
2015/03/14 Javascript
jQuery插件制作之参数用法实例分析
2015/06/01 Javascript
简介JavaScript中的getUTCFullYear()方法的使用
2015/06/10 Javascript
详解基于Vue-cli搭建的项目如何和后台交互
2018/06/29 Javascript
vue awesome swiper异步加载数据出现的bug问题
2018/07/03 Javascript
nginx配置域名后的二级目录访问不同项目的配置操作
2020/11/06 Javascript
vue打包通过image-webpack-loader插件对图片压缩优化操作
2020/11/12 Javascript
Java 生成随机字符的示例代码
2021/01/13 Javascript
Python复制目录结构脚本代码分享
2015/03/06 Python
python安装与使用redis的方法
2016/04/19 Python
Zabbix实现微信报警功能
2016/10/09 Python
使用python将大量数据导出到Excel中的小技巧分享
2018/06/14 Python
python3的输入方式及多组输入方法
2018/10/17 Python
Python网页正文转换语音文件的操作方法
2018/12/09 Python
Python实现正则表达式匹配任意的邮箱方法
2018/12/20 Python
python实战串口助手_解决8串口多个发送的问题
2019/06/12 Python
基于多进程中APScheduler重复运行的解决方法
2019/07/22 Python
Django ORM 聚合查询和分组查询实现详解
2019/08/09 Python
理解Django 中Call Stack机制的小Demo
2020/09/01 Python
Numpy中np.max的用法及np.maximum区别
2020/11/27 Python
Html5 语法与规则简要概述
2014/07/29 HTML / CSS
英国袜子店:Sock Shop
2017/01/11 全球购物
暑期社会实践个人总结
2015/03/06 职场文书
入伍志愿书怎么写?
2019/07/19 职场文书
大学学生会主席竞选稿怎么写?
2019/08/19 职场文书
详解Python中的进程和线程
2021/06/23 Python
Qt自定义Plot实现曲线绘制的详细过程
2021/11/02 Python
Python Matplotlib库实现画局部图
2021/11/17 Python