python super() 作用和原理

python 在类的继承中,当前类中如果方法与基类(父类)的方法一样,会覆盖基类的方法。

class Base(object):
    def run(self):
        print("Base start running~~")


class Dog(Base):
    def run(self):
        print("Dog start running~~")


if __name__ == "__main__":
    Dog().run()

# 结果
Dog start running~~

Process finished with exit code 0

上面代码代码中,基类Base 并没有执行,但是有些时候,定义基类就是把共同的代码写在一起,在调用当前方法是,我们基类中已经实现的公共部分。

类的继承

  1. 经典类(classic class) 基类名.方法名(self, *args, **kwargs), python版本低于2.2
  2. 新式类(new-style class) super(当前类名, self).方法名(*args, **kwargs), python 版本大于2.2
 1 class Base(object):
 2     def run(self):
 3         print("Now start running~~")
 4 
 5 class Dog(Base):
 6     def run(self):
 7         Base.run(self) # 经典类继承
 8         print("Dog start running~~")
 9 
10 if __name__ == "__main__":
11     Dog().run()
12 
13 # 结果
14 Now start running~~
15 Dog start running~~
16 
17 Process finished with exit code 0

当使用经典类继承时,Dog->Base->object 这种简单的继承顺序还可以,如果出现多重继承时,就会有下面的结果:

 1 class Base(object):
 2     def __init__(self):
 3         print("进入Base 类")
 4 
 5 
 6 class A(Base):
 7     def __init__(self):
 8         print("进入A 类")
 9         Base.__init__(self)
10 
11 
12 class B(Base):
13     def __init__(self):
14         print("进入B 类")
15         Base.__init__(self)
16 
17 
18 class C(A, B):
19     def __init__(self):
20         print("进入C 类")
21         A.__init__(self)
22         B.__init__(self)
23 
24 
25 if __name__ == "__main__":
26     c = C()

运行结果:

1 进入C 类
2 进入A 类
3 进入Base 类
4 进入B 类
5 进入Base 类
6 
7 Process finished with exit code 0

我们不难发现,执行顺序: C -> A -> Base -> B -> Base

是不是顺序有点蒙,我们理想状态的顺序难道不应该是: C -> A -> B -> Base (在继承多个类时,继承顺序从左往右依次继承)

如果按照理想状态运行应该怎么办, 我们就要用到 super 了。

super() 使用:

 1 class Base(object):
 2     def __init__(self):
 3         print("进入Base 类")
 4 
 5 
 6 class A(Base):
 7     def __init__(self):
 8         print("进入A 类")
 9         super(A, self).__init__()  # python2.7 的写法
10 
11 
12 class B(Base):
13     def __init__(self):
14         print("进入B 类")
15         super().__init__()
16 
17 
18 class C(A, B):
19     def __init__(self):
20         print("进入C 类")
21         super().__init__()  # python3 继承的写法
22 
23 
24 if __name__ == "__main__":
25     c = C()

结果:

1 进入C 类
2 进入A 类
3 进入B 类
4 进入Base 类
5 
6 Process finished with exit code 0

这样是不是就跟我们预想的一致了。

下面简单说一下super 是怎么运行的:

MRO 

简单说一下 MRO(Method Resolution Order),中文可以叫做 方法解析顺序,  在方法调用时,需要对当前类以及基类进行搜索确定方法位置。

在程序中可以使用:

 print(C.mro()) 

结果:

[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>]

python MRO

  • 经典类的深度遍历
  • python2 新式类的预计算
  • python3 新式类的C3线性化计算

python3 统一使用 C3 线性化算法,有兴趣的可以自行搜索。

小结

  • 在super机制里可以保证公共父类仅被执行一次
  • 执行的顺序,是按照MRO:方法解析顺序 进行的,执行完当前类按照mro 顺序执行下个类。

 

posted @ 2020-05-12 17:40  Simba辛巴  阅读(1603)  评论(0编辑  收藏  举报