python面向对象super()和mro机制

[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列表)
posted @ 2021-12-06 21:27  JasonBorn  阅读(63)  评论(0编辑  收藏  举报