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为tornado添加recaptcha验证码功能
Feb 26 Python
python开发中module模块用法实例分析
Nov 12 Python
python用户管理系统的实例讲解
Dec 23 Python
Python datetime和unix时间戳之间相互转换的讲解
Apr 01 Python
python 实现在一张图中绘制一个小的子图方法
Jul 07 Python
Tornado实现多进程/多线程的HTTP服务详解
Jul 25 Python
python实现智能语音天气预报
Dec 02 Python
使用celery和Django处理异步任务的流程分析
Feb 19 Python
Selenium向iframe富文本框输入内容过程图解
Apr 10 Python
tensorflow转换ckpt为savermodel模型的实现
May 25 Python
手把手教你将Flask应用封装成Docker服务的实现
Aug 19 Python
详解Python调用系统命令的六种方法
Jan 28 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 Ajax乱码
2008/04/09 PHP
PHP SPL使用方法和他的威力
2013/11/12 PHP
ThinkPHP中RBAC类的四种用法分析
2014/11/24 PHP
PHP设计模式之装饰者模式代码实例
2015/05/11 PHP
PHP微信API接口类
2016/08/22 PHP
php实现算术验证码功能
2018/12/05 PHP
HR vs ForZe BO3 第二场 2.13
2021/03/10 DOTA
js不是基础的基础
2006/12/24 Javascript
JQuery 常用操作代码
2010/03/14 Javascript
JQuery跨Iframe选择实现代码
2010/08/19 Javascript
几种延迟加载JS代码的方法加快网页的访问速度
2013/10/12 Javascript
JS实用的动画弹出层效果实例
2015/05/05 Javascript
Bootstrap项目实战之子栏目资讯内容
2016/04/25 Javascript
设计模式中的facade外观模式在JavaScript开发中的运用
2016/05/18 Javascript
JS求解三元一次方程组值的方法
2017/01/03 Javascript
jquery一键控制checkbox全选、反选或全不选
2017/10/16 jQuery
Vue下路由History模式打包后页面空白的解决方法
2018/06/29 Javascript
JS判断用户用的哪个浏览器实例详解
2018/10/09 Javascript
iview在vue-cli3如何按需加载的方法
2018/10/31 Javascript
js根据需要计算数组中重复出现某个元素的个数
2019/01/18 Javascript
ElementUI多个子组件表单的校验管理实现
2019/11/07 Javascript
JS数组方法slice()用法实例分析
2020/01/18 Javascript
怎么理解wx.navigateTo的events参数使用详情
2020/05/18 Javascript
Python实现从URL地址提取文件名的方法
2015/05/15 Python
使用Python脚本将文字转换为图片的实例分享
2015/08/29 Python
python3+PyQt5泛型委托详解
2018/04/24 Python
python os用法总结
2018/06/08 Python
Python走楼梯问题解决方法示例
2018/07/25 Python
html5+svg学习指南之SVG基础知识
2014/12/17 HTML / CSS
彪马日本官网:PUMA日本
2019/01/31 全球购物
索尼巴西商店:Sony巴西
2019/06/21 全球购物
Audible英国:有声读物,30天免费试用
2019/10/16 全球购物
银行爱岗敬业演讲稿
2014/05/05 职场文书
初中生旷课检讨书范文
2014/10/06 职场文书
大学生个人学年总结
2015/02/15 职场文书
win11无法添加打印机怎么办? 提示windows无法打开添加打印机的解决办法
2022/04/05 数码科技