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 解析XML python模块xml.dom解析xml实例代码
Feb 07 Python
跟老齐学Python之有点简约的元组
Sep 24 Python
Python获取当前路径实现代码
May 08 Python
python函数中return后的语句一定不会执行吗?
Jul 06 Python
Python实现读取json文件到excel表
Nov 18 Python
Python使用numpy产生正态分布随机数的向量或矩阵操作示例
Aug 22 Python
python导入pandas具体步骤方法
Jun 23 Python
Python 取numpy数组的某几行某几列方法
Oct 24 Python
利用python实现冒泡排序算法实例代码
Dec 01 Python
django连接mysql数据库及建表操作实例详解
Dec 10 Python
python怎么判断素数
Jul 01 Python
python使用Word2Vec进行情感分析解析
Jul 31 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
中东人咖啡哲学
2021/03/03 咖啡文化
php 邮件发送问题解决
2014/03/22 PHP
PHP连接Nginx服务器并解析Nginx日志的方法
2015/08/16 PHP
PHP递归遍历多维数组实现无限分类的方法
2016/05/06 PHP
关于Laravel Route重定向的一个注意点
2017/01/16 PHP
PHP命名空间与自动加载机制的基础介绍
2019/08/25 PHP
php的无刷新操作实现方法分析
2020/02/28 PHP
静态的动态续篇之来点XML
2006/12/23 Javascript
Add a Formatted Table to a Word Document
2007/06/15 Javascript
jQuery .attr()和.removeAttr()方法操作元素属性示例
2013/07/16 Javascript
浅析jQuery EasyUI中的tree使用指南
2014/12/18 Javascript
javascript实现动态标签云
2015/10/16 Javascript
JavaScript缓冲运动实现方法(2则示例)
2016/01/08 Javascript
js前端面试题及答案整理(一)
2016/08/26 Javascript
canvas红包照片实例分享
2017/02/28 Javascript
详解ES6之async+await 同步/异步方案
2017/09/19 Javascript
关于HTML5的data-*自定义属性的总结
2018/05/05 Javascript
JavaScript动态创建二维数组的方法示例
2019/02/01 Javascript
JS+php后台实现文件上传功能详解
2019/03/02 Javascript
解决cordova+vue 项目打包成APK应用遇到的问题
2019/05/10 Javascript
koa router 多文件引入的方法示例
2019/05/22 Javascript
vue 解除鼠标的监听事件的方法
2019/11/13 Javascript
vue 实现一个简单的全局调用弹窗案例
2020/09/10 Javascript
Vue+scss白天和夜间模式切换功能的实现方法
2021/01/05 Vue.js
[02:33]2018DOTA2亚洲邀请赛赛前采访——LGD
2018/04/04 DOTA
[02:51]DOTA2 Supermajor小组分组对阵抽签仪式
2018/06/01 DOTA
python类定义的讲解
2013/11/01 Python
python通过socket查询whois的方法
2015/07/18 Python
Python 实现还原已撤回的微信消息
2019/06/18 Python
jenkins+python自动化测试持续集成教程
2020/05/12 Python
CSS3 实现穿梭星空动画
2020/11/13 HTML / CSS
财务会计专业毕业生自荐信
2013/10/19 职场文书
预备党员政审材料
2014/02/04 职场文书
大班亲子运动会方案
2014/06/10 职场文书
仓库统计员岗位职责
2015/04/14 职场文书
如何利用STAR法则制作留学文书?
2019/08/26 职场文书