Python super()详解

news2026/4/2 2:51:11

python中的super()详解

文章目录

  • python中的super()详解
    • 概念
    • 作用
    • 语法原理
    • 常用具体语法形式
    • 注意
    • 案例代码
      • A -> B -> object
      • 棱形继承
      • 避免写`super(self.__class__, self)`
      • 避免把通过类名调用和super调用进行混合使用

概念

  • super是一个类
  • 只有在新式类中有效

作用

  • 起着代理的作用,帮我们完成下面的任务
  • 沿着MRO链条,找到下一级节点,去调用对应的方法

语法原理

  • 沿着谁的MRO链条?参数2
  • 找谁的下一个节点?参数1
  • 如何应对类方法、静态方法以及实例方法的传参问题?使用参数2进行调用

super(参数1[,参数2])

# 这是抽象表达的语法
def super(cls, inst):
    mro = inst.__class__.mro()
    return mro[mro.index(cls) + 1]
  • 首先,获取 参数2 所对应的类的MRO链条
  • 其次,获取 参数1 在这个上面这个MRO链条中的索引,并把索引进行+1
  • 最后,拿着被+1的索引在整个MRO链条中去找,这样也就找到了下一个节点

常用具体语法形式

大体分为三种:

  • super(type, obj) -> bound super object;:常用于调用其他类的实例方法,会把obj当作另外一个实例方法里面的参数(self)给传递过去。
  • super(type, type2) -> bound super object;:常用于调用其他类的类方法,会把type2当作对应的类方法里面的第一个参数(cls)给传递过去。
  • super():这是Python3特有的写法,会自动根据当前的上下文环境,即当前super代码所处于哪个类、当前处于哪个方法里。会自动帮我们取到对应的类名和当前所在方法的第一个参数,自动的填充进来。

注意

案例代码

A -> B -> object

# 笨拙方法
# 有一个问题就是当B类的类名发生改变时,我们要改一下A类的代码才行
class B:
    def __init__(self):
        self.b = 2
        self.xxx = "123"
class A(B):
    def __init__(self):
        B.__init__(self)
        self.a = 1
if __name__ == "__main__":
    a = A()
    print(a.__dict__)  # {'b': 2, 'xxx': '123', 'a': 1}
# 使用super
# 可以解决B类的类名发生改变时,A类中的代码不需要变的问题
class B:
    def __init__(self):
        self.b = 2
        self.xxx = "123"
class A(B):
    def __init__(self):
        # super的参数2必须为A类或A类的子类的实例对象,因为super参数2将会作为参数自动的传递给后面的__init__方法
        # 因为self作为A类的实例所以在A类的MRO链条中,根据参数1找下一个索引也就是B类的__init__方法
        # 这样这个self才会在B类的__init__方法中被赋值self.b=2和self.xxx="123"
        super(A, self).__init__()
        self.a = 1
if __name__ == "__main__":
    a = A()
    print(a.__dict__)  # {'b': 2, 'xxx': '123', 'a': 1}
# python3.x
class B:
    def __init__(self):
        self.b = 2
        self.xxx = "123"
class A(B):
    def __init__(self):
        # 相当于这样写: super(__class__, <first argument>)
        # 也就是: super(__class__, self)
        # __class__就是当前所在的类名
        # <first argument>就是super所在方法的第一个参数也就是self
        super().__init__()
        # super(__class__, self)
        self.a = 1
if __name__ == "__main__":
    a = A()
    print(a.__dict__)  # {'b': 2, 'xxx': '123', 'a': 1}
# python3.x
class B:
    def __init__(self):
        self.b = 2
        self.xxx = "123"
    @classmethod
    def t1(cls):
        print(cls) # <class '__main__.A'>
        print("t1")
class A(B):
    def __init__(self):
        super().__init__()
        self.a = 1
    @classmethod
    def t2(cls):
        super(A, A).t1() # t1
        super(A, cls).t1() # t1
        super(cls, cls).t1() # t1
        super().t1() # t1
        print("t2") # t2
if __name__ == "__main__":
    a = A()
    print(a.__dict__)  # {'b': 2, 'xxx': '123', 'a': 1}
    A.t2()

棱形继承

# 注意:这里会有个问题,使用类名去调用,会产生重复调用的问题
class D(object):
    def __init__(self):
        print("d")
class B(D):
    def __init__(self):
        D.__init__(self)
        print("b")
class C(D):
    def __init__(self):
        D.__init__(self)
        print("c")
class A(B, C):
    def __init__(self):
        B.__init__(self)
        C.__init__(self)
        print("a")
if __name__ == '__main__':
    # [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]
    print(A.mro())
    a = A()
# d
# b
# d
# c
# a
# 使用super, 完美解决重复调用的问题,而且也保证A类创建实例后拥有所有父类资源
class D(object):
    def __init__(self):
        print("d")
class B(D):
    def __init__(self):
        super().__init__()
        print("b")
class C(D):
    def __init__(self):
        super().__init__()
        print("c")
class A(B, C):
    def __init__(self):
        super().__init__()
        print("a")
if __name__ == '__main__':
    # [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]
    print(A.mro())
    a = A()
# d
# c
# b
# a

"""
这里之所以是这样的打印顺序是因为A的MRO链条就是: A -> B -> C -> D -> object
A中在执行__init__方法的super时,是找A当前的MRO链条的下一个也就是B,
找到B的__init__方法时执行B的super,是找B当前的MRO链条的下一个也就是C,
找到C的__init__方法时执行C的super,是找C当前的MRO链条的下一个也就是D,
找到D的__init__方法后没有super了,就开始执行D的__init__方法
然后再从C的__init__方法中执行super后面的代码
然后再从B的__init__方法中执行super后面的代码
最后再执行A的__init__方法中执行super后面的代码
"""

避免写super(self.__class__, self)

# 会报错:RecursionError: maximum recursion depth exceeded while calling a Python object
# 因为self是不稳定的!!!!!
class D(object):
    def __init__(self):
        print("d")
# 有的大聪明:
# 会觉得如果写super(B, self).__init__()时,B的类名改了,那么不好编码
# 大聪明灵机一动写:super(self.__class__, self) ,注意会有问题哦!
class B(D):
    def __init__(self):
        # 因为这里的self是A实例,相当于是super(A, A实例),所以找到的MRO链条的下一个节点还是B自己,所以这里就会不断的调用相同的方法,就产生了死循环调用,就报错了
        super(self.__class__, self).__init__()
        print("b")
class C(D):
    def __init__(self):
        super().__init__()
        print("c")
class A(B, C):
    def __init__(self):
        super().__init__()
        print("a")
if __name__ == '__main__':
    # [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]
    print(A.mro())
    a = A()

避免把通过类名调用和super调用进行混合使用

class D(object):
    def __init__(self):
        print("d")
class B(D):
    def __init__(self): # self: <__main__.A object at 0x10ebcdd90>
        # 等同于super(B, a实例)
        # 在A的MRO链条上找B的下一个节点也就是C
        super().__init__()
        print("b")
class C(D):
    def __init__(self): # self: <__main__.A object at 0x10ebcdd90>
        # 等同于super(C, a实例)
        # 在A的MRO链条上找C的下一个节点也就是D
        super().__init__()
        print("c")
class A(B, C):
    def __init__(self): # self: <__main__.A object at 0x10ebcdd90>
        B.__init__(self) # 我们只讲这一行,参考注释即可
        C.__init__(self)
        print("a")
if __name__ == '__main__':
    # [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]
    print(A.mro())
    a = A()
# d
# c
# b
# d
# c
# a

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1293568.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

快速排序的非递归实现

上期我们实现了快速排序的递归实现&#xff0c;但是我们知道如果递归深度太深&#xff0c;栈就会溢出&#xff0c;所以我们本期将为大家讲述快速排序的非递归实现&#xff0c;我们需要用到栈的数据结构&#xff0c;我们知道栈中的数据全是在堆区开辟的空间&#xff0c;堆的空间…

【EXCEL】offset函数

语法&#xff1a; offset(reference,row,column,[height],[width]) 例子&#xff1a;

【日常总结】mybatis-plus WHERE BINARY 中文查不出来

目录 一、场景 二、问题 三、原因 四、解决方案 五、拓展&#xff08;全表全字段修改字符集一键更改&#xff09; 准备工作&#xff1a;做好整个库备份 1. 全表一键修改 Stage 1&#xff1a;运行如下查询 Stage 2&#xff1a;复制sql语句 Stage 3&#xff1a;执行即可…

Volumetric Lights 2 HDRP

高清晰度渲染管道,包括先进的新功能,如半透明阴影图和直接灯光投射加上许多改进。 插件是一个快速,灵活和伟大的前瞻性光散射解决方案的高清晰度渲染管道。只需点击几下,即可改善场景中的照明视觉效果。 兼容: 点光源 聚光灯 碟形灯 矩形灯 通过覆盖摄像机周围大面积区域的…

05 JQuery基础入门

文章目录 一、jQuery介绍1. 简介2. 版本介绍3. 相关网站4. HTML引入方式 二、基础语法1. 顶级对象$2. 与DOM对象转化3. 选择器4. 事件5. 动画6. 修改样式7. 修改属性 一、jQuery介绍 1. 简介 jQuery是JavaScript编程语言底层库&#xff0c;它是一个快速&#xff0c;简洁的Jav…

JavaScript <关于逆向RSA非对称加密算法的案例(附原代码)>--案例(五)

前言: 趁热打铁,标记一下RSA的算法逆向...第二篇会有详解(本篇重在过程) 正文: 废话不说,直接分析步骤图: 到了这里,可以看到在登录的时候,需要验证码(本篇不教反验证码) 下面是正题--->逆他的pwd(密码) 总结: 问题:怎么确定一个密文数据是基于什么算法做出来的呢? 答:…

python 涉及opencv mediapipe知识,眨眼计数 供初学者参考

基本思路 我们知道正面侦测到人脸时&#xff0c;任意一只眼睛水平方向上的两个特征点构成水平距离&#xff0c;上下两个特征点构成垂直距离 当头像靠近或者远离摄像头时&#xff0c;垂直距离与水平距离的比值基本恒定 根据这一思路 当闭眼时 垂直距离变小 比值固定小于某一个…

Abaqus基础教程--胶合失效仿真

胶合是电子行业中常见的连接方式&#xff0c;abaqus中常用cohesive单元或者cohesive接触两种方法进行胶合失效仿真&#xff0c;这两种方式操作方法有所差别&#xff0c;但结果一般大同小异。 本例模型比较简单&#xff0c;建模过程从略&#xff0c;使用静态分析&#xff0c;使…

python基于ModBusTCP服务端的业务实现特定的client

python实现ModBusTCP协议的client是一件简单的事情&#xff0c;只要通过pymodbus、pyModbusTCP等模块都可以实现&#xff0c;本文采用pymodbus。但要基于ModBusTCP服务端的业务实现特定的client&#xff0c;那得看看服务端是否复杂。前面系列文章&#xff0c;我们学习了对服务端…

【vtkWidgetRepresentation】第五期 vtkLineRepresentation

很高兴在雪易的CSDN遇见你 内容同步更新在公众号“VTK忠粉” 【vtkWidgetRepresentation】第五期 一条直线的交互 前言 本文分享vtkLineRepresentation&#xff0c;希望对各位小伙伴有所帮助&#xff01; 感谢各位小伙伴的点赞关注&#xff0c;小易会继续努力分享&#xf…

Python---继承

1、什么是继承 我们接下来来聊聊Python代码中的“继承”&#xff1a;类是用来描述现实世界中同一组事务的共有特性的抽象模型&#xff0c;但是类也有上下级和范围之分&#xff0c;比如&#xff1a;生物 > 动物 > 哺乳动物 > 灵长型动物 > 人类 > 黄种人 从哲学…

Go--协程

协程 协程是Go语言最大的特色之一。 1、协程的概念 协程并不是Go发明的概念&#xff0c;支持协程的变成语言有很多。Go在语言层面直接提供对协程的支持称为goroutine。 1.1 基本概念 进程 进程是应用程序启动的实例&#xff0c;每个进程都有独立的内存空间&#xff0c;不同…

DSP外部中断笔记

中断原理 三部分 注意 &#xff0c;外部中断使能&#xff0c;PIE使能&#xff0c;CPU中断使能 外部中断有7个&#xff0c;PIE有12组&#xff0c;一个组有8个中断复用。只有一个CPU中断可执行。 外部中断原理 1、外部中断概述 外部中断结构图 外部中断XINT1对应的是0到31GPI…

<IBM Websphere Portal>《关于IBM的Portal和WAS的说明和总结(自用笔记)》

《关于IBM的Portal和WAS的简单总结》 1 架构1.1 说明 2 常见问题2.1 LDAP链接问题2.2 启动脚本建议2.3 日志大小保留建议2.4 启动垃圾回收日志 3 日志位置 1 架构 应用服务部署架构如上&#xff1a; &#x1f449;192.168.66.1服务器运行的server进程有&#xff1a;dmgr、nodea…

360压缩安装一半不动了怎么办?

360压缩软件是我们常用的压缩软件&#xff0c;但是常常会遇到压缩安装到一半停止的情况&#xff0c;下面提供了一些可能的原因和解决办法&#xff0c;大家可以进行尝试~ 方法一&#xff1a;关闭防火墙和杀毒软件 有时候&#xff0c;防火墙和杀毒软件可能会阻止360压缩的安装过…

为什么 SQL 不适合图数据库

背景 “为什么你们的图形产品不支持 SQL 或类似 SQL 的查询语言&#xff1f;” 过去&#xff0c;我们的一些客户经常问这个问题&#xff0c;但随着时间的推移&#xff0c;这个问题变得越来越少。 尽管一度被忽视&#xff0c;但图数据库拥有无缝设计并适应其底层数据结构的查询…

Docker实战笔记 二 Springboot Idea 插件打包

1.上传springboot的jar rootcenots-7.5:/home/code#rz -----app.jar 2.编辑Dockerfile rootcenots-7.5:/home/code#vi Dockerfile内容 FROM openjdk:8 # 作者 MAINTAINER nnd # 声明要使用的端口 EXPOSE 8080 # VOLUME 指定了临时文件目录为/tmp。# 将本地包添加到容器中并…

服装收银系统哪个最好用

服装订货系统哪个最好&#xff0c;可能没有一个标准的答案&#xff0c;但至少可以从以下几点进行选择&#xff1a; 1、数据批量操作&#xff1a;服装到货都是一批一批&#xff0c;如果能将条码进行批量导入&#xff0c;这样在这里耗去的时间就少很多了&#xff0c;剩下的是时间…

在Windows 11中更改文件的扩展名有几种办法,个别办法可以批量修改

本文介绍了如何在Windows 11中更改文件的文件扩展名。 用简单的方法更改文件扩展名 对于大多数人来说&#xff0c;在Windows 11中更改文件扩展名的最简单方法是在更改文件名的同一个地方进行更改。然而&#xff0c;Windows默认情况下不显示文件扩展名&#xff0c;所以在我们可…

【Flink系列三】数据流图和任务链计算方式

上文介绍了如何计算并行度和slot的数量&#xff0c;本文介绍Flink代码提交后&#xff0c;如何生成计算的DAG数据流图。 程序和数据流图 所有的Flink程序都是由三部分组成的&#xff1a;Source、Transformation和Sink。Source负责读取数据源&#xff0c;Transformation利用各种…