[moc]
super()和mro列表
super()
# 在python中super一般用在继承中,通过super我们可以调用父类。
# 这段代码中定义了一个子类Son,它继承与父类Father,实例化对象可以调用父类中的__init__方法
class Father():
def __init__(self):
print("这是父类的")
class Son(Father):
def __init__(self):
Father.__init__(self) # 调用父类的__init__ 类的调用需要传入参数self
print("这是子类的")
son = Son()
打印出:这是父类的
这是子类的
'''
通过这样调用父类,我们就实现了既可以调用子类方法,也可以调用父类方法。如果不这样调用的话,当子类继承一个父类的时候,使用__init__方法的话,子类就会覆盖父类,我们就无法访问父类的__init__方法。
'''
! 通过super()实现上述代码
class Father(): # Father为父类
def __init__(self):
print("这是父类的")
class Son(Father): # Father为Son的父类
def __init__(self):
super(Son, self).__init__() # 这里使用super()语句 实现相同的效果
super().__init__() # python3中super()括号内无需传入参数
print("这是子类的")
son = Son() # 类的实例化对象
打印出:这是父类的
这是子类的
# 当我们使用super方法时,我们需要在super中传入子类的类名和self,无需再__init__方法中传入self 可以看到和上面的结果是一样的
使用super()的好处
## 为什么上边的可以实现 还要使用super()呢
示例:
class Grandfather(): # Grandfather为父类 #这里修改了原先的父类
def __init__(self):
print("这是父类的")
class Son(Grandfather): # Grandfather为Son的父类
def __init__(self):
super(Son, self).__init__()
print("这是子类的")
son = Son() # 类的实例化对象
这是父类的
这是子类的
'''
这样我们可以看到,当我们修改了Son继承的父类时,代码的结果仍然时相同的,我们不需要修改内部的内名.用第一种方法时有一个不好的地方就是,需要将父类名写到子类中,而我们用super方法就可以解决这个问题。
'''
mro机制
'''
事实上,在每个类声明之后,Python都会自动为创建一个名为“__mro__”的内置属性,这个属性就是Python的MRO机制生成的,该属性是一个tuple,定义的是该类的方法解析顺序(继承顺序),
当用super调用父类的方法时,会按照__mro__属性中的元素顺序去挨个查找方法。我们可以通过“类名.__mro__”或“类名.mro()”来查看代码中类的__mro__属性值
'''
本质上:这个顺序是怎么生成的呢?在Python新式类中(Python3中也只存在新式类了),采用的是C3算法(可不是广度优先,更不是深度优先)。
#A没有继承B,但是A内super会基于C.mro()继续往后找
class A:
def test(self):
print('A---->test')
super().aaa()
class B:
def test(self):
print('B---->test')
def aaa(self):
print('B---->aaa')
class C(A,B):
def aaa(self):
print('C----->aaa')
c=C()
c.test() #打印结果:
'''
A---->test
B---->aaa
'''
print(C.mro())
#打印结果为:
#[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
# C作为方法调用(即c.test())的发起者,方法调用过程中涉及的属性查找都参考C.mro()。父子关系按照mro列表为准,千万不要从代码层面看父子。例如
# c.test(),发起者C.mro()列表如下,从列表中可以看出,B类就是A类的父类,而代码层面二者并无继承关系
注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)