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实现协同过滤的教程
Apr 08 Python
python使用Tkinter显示网络图片的方法
Apr 24 Python
实例讲解Python的函数闭包使用中应注意的问题
Jun 20 Python
使用Python通过win32 COM打开Excel并添加Sheet的方法
May 02 Python
浅谈python中对于json写入txt文件的编码问题
Jun 07 Python
Python 字符串换行的多种方式
Sep 06 Python
python+opencv实现摄像头调用的方法
Jun 22 Python
Python3 venv搭建轻量级虚拟环境的步骤(图文)
Aug 09 Python
python+Django实现防止SQL注入的办法
Oct 31 Python
Django自带的加密算法及加密模块详解
Dec 03 Python
django框架基于queryset和双下划线的跨表查询操作详解
Dec 11 Python
python怎么提高计算速度
Jun 11 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
dedecms系统常用术语汇总
2007/04/03 PHP
php 方便水印和缩略图的图形类
2009/05/21 PHP
Ping服务的php实现方法,让网站快速被收录
2012/02/04 PHP
基于magic_quotes_gpc与magic_quotes_runtime的区别与使用介绍
2013/04/22 PHP
利用PHP如何写APP接口详解
2016/08/23 PHP
Codeigniter里的无刷新上传的实现代码
2019/04/14 PHP
PHP实现随机发扑克牌
2020/04/22 PHP
用JQuery 实现AJAX加载XML并解析的脚本
2009/07/25 Javascript
jQuery替换字符串(实例代码)
2013/11/13 Javascript
在Html中使用Requirejs进行模块化开发实例详解
2016/04/15 Javascript
利用jquery实现验证输入的是否是数字、小数,包含保留几位小数
2016/12/07 Javascript
利用BootStrap的Carousel.js实现轮播图动画效果
2016/12/21 Javascript
详解JS异步加载的三种方式
2017/03/07 Javascript
对vue中methods互相调用的方法详解
2018/08/30 Javascript
JS实现在线ps功能详解
2019/07/31 Javascript
vue 实现根据data中的属性值来设置不同的样式
2020/08/04 Javascript
[16:04]DOTA2海涛带你玩炸弹 9月5日更新内容详解
2014/09/05 DOTA
python算法学习之基数排序实例
2013/12/18 Python
Python中zip()函数用法实例教程
2014/07/31 Python
简单的Python2.7编程初学经验总结
2015/04/01 Python
Python实现以时间换空间的缓存替换算法
2016/02/19 Python
python3之微信文章爬虫实例讲解
2017/07/12 Python
python的set处理二维数组转一维数组的方法示例
2019/05/31 Python
python区块及区块链的开发详解
2019/07/03 Python
python爬虫模块URL管理器模块用法解析
2020/02/03 Python
全球最大的生存食品、水和装备专用在线市场:BePrepared.com
2020/01/02 全球购物
触发器(trigger)的功能都有哪些?写出一个触发器的例子
2012/09/17 面试题
会计电算化专业个人的自我评价
2013/11/24 职场文书
四川成都导游欢迎词
2014/01/18 职场文书
管理学院毕业生自荐信范文
2014/03/10 职场文书
立志成才演讲稿
2014/09/04 职场文书
思想工作总结范文
2015/08/12 职场文书
心得体会该怎么写呢?
2019/06/27 职场文书
mysql的MVCC多版本并发控制的实现
2021/04/14 MySQL
mybatis-plus模糊查询指定字段
2022/04/28 Java/Android
我国拿下天问一号火星着陆区附近 22 个地理实体命名:平乐、西柏坡、古田、漠河等
2022/04/29 数码科技