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 相关文章推荐
phpsir 开发 一个检测百度关键字网站排名的python 程序
Sep 17 Python
Python实现全角半角转换的方法
Aug 18 Python
Python简单进程锁代码实例
Apr 27 Python
Python实现配置文件备份的方法
Jul 30 Python
Python实现PS图像调整之对比度调整功能示例
Jan 26 Python
PyQt5的PyQtGraph实践系列3之实时数据更新绘制图形
May 13 Python
python如何统计代码运行的时长
Jul 24 Python
Python 用三行代码提取PDF表格数据
Oct 13 Python
python实现两个字典合并,两个list合并
Dec 02 Python
Python打包工具PyInstaller的安装与pycharm配置支持PyInstaller详细方法
Feb 27 Python
Python偏函数实现原理及应用
Nov 20 Python
Pytorch 使用tensor特定条件判断索引
Apr 08 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的网址
2006/11/25 PHP
php实现建立多层级目录的方法
2014/07/19 PHP
如何修改yii2.0自带的user表为其它的表
2017/08/01 PHP
PHP PDOStatement::bindColumn讲解
2019/01/30 PHP
PHP下用Swoole实现Actor并发模型的方法
2019/06/12 PHP
jQuery 使用个人心得
2009/02/26 Javascript
js监听输入框值的即时变化onpropertychange、oninput
2011/07/13 Javascript
JavaScript高级程序设计 DOM学习笔记
2011/09/10 Javascript
使用闭包对setTimeout进行简单封装避免出错
2013/07/10 Javascript
jquery实现具有收缩功能的垂直导航菜单
2016/02/16 Javascript
js面向对象编程总结
2017/02/16 Javascript
webpack学习--webpack经典7分钟入门教程
2017/06/28 Javascript
微信小程序修改swiper默认指示器样式的实例代码
2018/07/18 Javascript
vue中当图片地址无效的时候,显示默认图片的方法
2018/09/18 Javascript
基于jquery实现九宫格拼图小游戏
2018/11/30 jQuery
spring+angular实现导出excel的实现代码
2019/02/27 Javascript
layui上传图片到服务器的非项目目录下的方法
2019/09/26 Javascript
JavaScript实现电灯开关小案例
2020/03/30 Javascript
JavaScript实现简单动态表格
2020/12/02 Javascript
JS实现简易日历效果
2021/01/25 Javascript
[48:21]Mski vs VGJ.S Supermajor小组赛C组 BO3 第一场 6.3
2018/06/04 DOTA
Python中使用Inotify监控文件实例
2015/02/14 Python
pandas 中对特征进行硬编码和onehot编码的实现
2019/12/20 Python
CSS3实现头像旋转效果
2017/03/13 HTML / CSS
css3中less实现文字长阴影(long shadow)
2020/04/24 HTML / CSS
美国照明、家居装饰和家具购物网站:Bellacor
2017/09/20 全球购物
西班牙床垫网上商店:Colchones.es
2018/05/06 全球购物
英国健身超市:Fitness Superstore
2019/06/17 全球购物
新大陆软件面试题
2016/11/24 面试题
成功经营餐厅的创业计划书范文
2013/12/26 职场文书
2014的自我评价
2014/01/13 职场文书
新员工入职感言
2014/02/01 职场文书
采购经理岗位职责
2014/02/16 职场文书
普通话演讲稿
2014/09/03 职场文书
2014年居委会工作总结
2014/12/09 职场文书
实体类或对象序列化时,忽略为空属性的操作
2021/06/30 Java/Android