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



















