[moc]
# 在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()呢
示例: class Grandfather(): # Grandfather为父类 #这里修改了原先的父类 def __init__(self): print("这是父类的") class Son(Grandfather): # Grandfather为Son的父类 def __init__(self): super(Son, self).__init__() print("这是子类的") son = Son() # 类的实例化对象 这是父类的 这是子类的 ''' 这样我们可以看到,当我们修改了Son继承的父类时,代码的结果仍然时相同的,我们不需要修改内部的内名.用第一种方法时有一个不好的地方就是,需要将父类名写到子类中,而我们用super方法就可以解决这个问题。 '''
''' 事实上,在每个类声明之后,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列表)