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的Django框架中的静态资源管理器django-pipeline
Apr 25 Python
详解Python安装scrapy的正确姿势
Jun 26 Python
Python 绘制酷炫的三维图步骤详解
Jul 12 Python
python误差棒图errorbar()函数实例解析
Feb 11 Python
Django使用list对单个或者多个字段求values值实例
Mar 31 Python
浅析python 定时拆分备份 nginx 日志的方法
Apr 27 Python
python中使用input()函数获取用户输入值方式
May 03 Python
Python OpenCV实现测量图片物体宽度
May 27 Python
浅析NumPy 切片和索引
Sep 02 Python
PyCharm中关于安装第三方包的三个建议
Sep 17 Python
Python + opencv对拍照得到的图片进行背景去除的实现方法
Nov 18 Python
一篇文章教你用python画动态爱心表白
Nov 22 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
从零开始的异世界生活:第二季延期后,B站上架了第二部剧场版
2020/05/06 日漫
基于PHP+MySQL的聊天室设计
2006/10/09 PHP
PHP开发中常用的字符串操作函数
2011/02/08 PHP
php加水印的代码(支持半透明透明打水印,支持png透明背景)
2013/01/17 PHP
免费手机号码归属地API查询接口和PHP使用实例分享
2014/04/10 PHP
Javascript 面向对象编程(coolshell)
2012/03/18 Javascript
nodejs的10个性能优化技巧
2014/07/15 NodeJs
用JavaScript显示浏览器客户端信息的超相近教程
2015/06/18 Javascript
jQuery获取复选框被选中数量及判断选择值的方法详解
2016/05/25 Javascript
JS控制静态页面传递参数并获取参数应用
2016/08/10 Javascript
利用js+css+html实现固定table的列头不动
2016/12/08 Javascript
canvas绘制的直线动画
2017/01/23 Javascript
H5+css3+js搭建带验证码的登录页面
2020/10/11 Javascript
Python使用剪切板的方法
2017/06/06 Python
对pandas中apply函数的用法详解
2018/04/10 Python
对python numpy.array插入一行或一列的方法详解
2019/01/29 Python
python里dict变成list实例方法
2019/06/26 Python
Django框架序列化与反序列化操作详解
2019/11/01 Python
Python模块的定义,模块的导入,__name__用法实例分析
2020/01/07 Python
Python3查找列表中重复元素的个数的3种方法详解
2020/02/13 Python
Python流程控制语句的深入讲解
2020/06/15 Python
python软件都是免费的吗
2020/06/18 Python
利用python清除移动硬盘中的临时文件
2020/10/28 Python
x-ua-compatible content=”IE=7, IE=9″意思理解
2013/07/22 HTML / CSS
移动端HTML5实现文件上传功能【附代码】
2016/03/25 HTML / CSS
初中生个人学习的自我评价
2013/12/04 职场文书
致200米运动员广播稿
2014/02/06 职场文书
小学生读书感言
2014/02/12 职场文书
课堂教学改革实施方案
2014/03/17 职场文书
学校创先争优活动总结
2014/08/28 职场文书
社区义诊通知
2015/04/24 职场文书
幼儿园万圣节活动总结
2015/05/05 职场文书
辩论赛主持人开场白
2015/05/29 职场文书
公诉意见书范文
2015/06/05 职场文书
spring cloud gateway中如何读取请求参数
2021/07/15 Java/Android
【DOTA2】半决赛强强对话~ PSG LGD vs EHOME - DPC 2022 CN REGIONAL FINALS WINTER
2022/04/02 DOTA