我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈
入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈
虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈
PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈
Oracle数据库教程:👉👉 Oracle数据库文章合集 👈👈
优 质 资 源 下 载 :👉👉 资源下载合集 👈👈
Python面向对象_self_cls_super
- self
- cls
- super
self
cls
super
-
继承关系中,在低优先级类的方法中通过
super
调用高优先级类的方法 -
概念
- 是一个类,只有在新式类中有效
-
作用
- 起着代理的作用,沿着MRO链条,找到下一节点,去调用对应的方法
- 在其他语言中会把
super
认定是父类,但是Python是支持多继承的,所以在Python中super
与父类并没有直接的关系,完全是按照MRO链条来的
-
问题点
- 沿着谁的MRO链条查找?
- 找到谁的下一个节点?
- 调用方法时,类方法、静态方法、实例方法的传参问题
-
语法原理
- 语法
super(参数1[, 参数2])
- 工作原理
def super(cls, inst): mro = inst.__class__.mro() return mro[mro.index(cls) + 1] # inst.__class__ # 获取第二个参数inst对象对应的类对象 # inst.__class__.mro() # 获取对应类对象的mro链条,返回一个列表 # mro示例:[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>] # mro.index(cls) # 获取指定类对象在这个mro链条列表中的索引位置 # mro.index(cls) + 1 # 获取指定类对象的下一个节点索引号 # mro[mro.index(cls) + 1] # 根据索引号获取mro链条列表中下一个节点的类对象
- 语法
-
问题解决
- 沿着谁的MRO链条查找? ————> 参数2
- 找到谁的下一个节点? ————> 参数1
- 调用方法时,类方法、静态方法、实例方法的传参问题 ————> 使用参数2进行调用
-
常用语法形式
# 在Python2.2+ super(type, obj) # 一般调用其他类的实例方法,会把这个obj传递另外一个类的实例方法中的第一个参数 super(type, type2) # 一般调用其他类的类方法,会把这个type2传递另外一个类的类方法中的第一个参数cls # 只能在Python3+中使用,仅新式类可用 super() # 仅仅适用于写在类定义的内部,会自动的根据当前所在的类和方法里面,取到对应的类名和方法的第一个参数自动填充进去
-
示例1:调用实例方法
class B(object): def __init__(self): self.b = 'b' class A(B): def __init__(self): super(A, self).__init__() # def super(cls, inst): # mro = inst.__class__.mro() # return mro[mro.index(cls) + 1] # 首先确定是要调用的B的__init__方法,先确定B是谁的下一级,B是A的下一级,所以第一个参数传A # 需要在这个mro链条中通过A的索引获取到下一级的索引,那么谁的mro链条中会有A呢?要么是A,要么是A的实例,或者是A的子类 # 这里要调用的是B的__init__方法,这个__init__方法的参数需要一个类实例对象,所以我们可以通过A的实例(self)来获取mro链条 # super函数的第二个参数会直接作为调用的实例方法的第一个参数传递过去,所以__init__方法后面可以不加self参数了 self.a = 'a' a = A() print(a.__dict__) # {'b': 'b', 'a': 'a'}
-
示例2:调用类方法
class B(object): @classmethod def t1(cls): print(cls) print('t1') class A(B): @classmethod def tt1(cls): super(A, cls).t1() print('tt1') # def super(cls, inst): # mro = inst.__class__.mro() # return mro[mro.index(cls) + 1] # 首先确定是要调用的B的t1()方法,先确定B是谁的下一级,B是A的下一级,所以第一个参数传A # 需要在这个mro链条中通过A的索引获取到下一级的索引,那么谁的mro链条中会有A呢?要么是A,要么是A的实例,或者是A的子类 # 这里要调用的是B的t1()方法,这个t1(cls)方法的参数需要一个类对象,所以我们可以通过A这个类来获取mro链条 # super函数的第二个参数会直接作为调用的类方法的第一个参数传递过去,所以super(A, cls).t1()方法后面可以不加cls参数了 a = A() a.tt1() # 输出结果 # <class '__main__.A'> # 执行 super(A, cls).t1() 调用B内部的 t1(),打印cls,这里的cls就是super函数中给的第二个参数 # t1 # 执行 super(A, cls).t1() 调用B内部的 t1(),打印 't1' # tt1 # 执行 print('tt1')
-
示例3:调用静态方法
class B(object): @staticmethod def t1(n): print(n) print('t1') class A(B): @staticmethod def tt1(name): super(A, A).t1(name) print('tt1') # def super(cls, inst): # mro = inst.__class__.mro() # return mro[mro.index(cls) + 1] # 首先确定是要调用的B的t1()方法,先确定B是谁的下一级,B是A的下一级,所以第一个参数传A # 需要在这个mro链条中通过A的索引获取到下一级的索引,那么谁的mro链条中会有A呢?要么是A,要么是A的实例,或者是A的子类 # 这里要调用的是B的t1()方法,这个t1(n)方法的参数需要一个值,在静态方法中我们拿不到实例对象self,也没有cls,所以只能传A或者A的子类 # B内部的t1(n)方法需要接收一个参数,所以super(A, A).t1(name)方法后面需要添加参数传递 a = A() a.tt1('失心疯') # 输出结果 # 失心疯 # t1 # tt1