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中实现从目录中过滤出指定文件类型的文件
Feb 02 Python
理解Python中的类与实例
Apr 27 Python
python使用htmllib分析网页内容的方法
May 08 Python
Python脚本实时处理log文件的方法
Nov 21 Python
python中多层嵌套列表的拆分方法
Jul 02 Python
python得到qq句柄,并显示在前台的方法
Oct 14 Python
详解python中的Turtle函数库
Nov 19 Python
Python django框架应用中实现获取访问者ip地址示例
May 17 Python
简单的Python调度器Schedule详解
Aug 30 Python
python 命名规范知识点汇总
Feb 14 Python
pycharm设置默认的UTF-8编码模式的方法详解
Jun 01 Python
python如何实现word批量转HTML
Sep 30 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中查询SQL Server或Sybase时TEXT字段被截断的解决方法
2009/03/10 PHP
php自动注册登录验证机制实现代码
2011/12/20 PHP
MySQL 日期时间函数常用总结
2012/06/12 PHP
PHPExcel实现表格导出功能示例【带有多个工作sheet】
2018/06/13 PHP
PHP 实现链式操作
2021/03/09 PHP
JavaScript初学者应注意的七个细节小结
2012/01/30 Javascript
jQuery的live()方法对hover事件的处理示例
2014/02/27 Javascript
浅谈Unicode与JavaScript的发展史
2015/01/19 Javascript
js树插件zTree获取所有选中节点数据的方法
2015/01/28 Javascript
JavaScript比较两个对象是否相等的方法
2015/02/06 Javascript
jquery实现实时改变网页字体大小、字体背景色和颜色的方法
2015/08/05 Javascript
Bootstrap精简教程
2015/11/27 Javascript
JavaScript中的this引用(推荐)
2016/08/05 Javascript
Javascript 调用 ActionScript 的简单方法
2016/09/22 Javascript
JS经典正则表达式笔试题汇总
2016/12/15 Javascript
tab栏切换原理
2017/03/22 Javascript
Bootstrap Tooltip显示换行和左对齐的解决方案
2017/10/11 Javascript
javascript标准库(js的标准内置对象)总结
2018/05/26 Javascript
JS/HTML5游戏常用算法之路径搜索算法 随机迷宫算法详解【普里姆算法】
2018/12/13 Javascript
一百行JS代码实现一个校验工具
2019/04/30 Javascript
微信小程序+腾讯地图开发实现路径规划绘制
2019/05/22 Javascript
vue点击页面空白处实现保存功能
2019/11/06 Javascript
javascript使用Blob对象实现的下载文件操作示例
2020/04/18 Javascript
何时/使用 Vue3 render 函数的教程详解
2020/07/25 Javascript
vue 动态添加的路由页面刷新时失效的原因及解决方案
2021/02/26 Vue.js
Python判断文件和字符串编码类型的实例
2017/12/21 Python
python操作列表的函数使用代码详解
2017/12/28 Python
Python实现Event回调机制的方法
2019/02/13 Python
儿子婚宴答谢词
2014/01/09 职场文书
决心书范文
2014/03/11 职场文书
2014客服代表实习自我鉴定
2014/09/18 职场文书
小学教师自我评价
2015/03/04 职场文书
Python集合的基础操作
2021/11/01 Python
Mysql忘记密码解决方法
2022/02/12 MySQL
JavaScript实现外溢动态爱心的效果的示例代码
2022/03/21 Javascript
Selenium浏览器自动化如何上传文件
2022/04/06 Python