python super()

super()入门级用法还是比较简单的.

在类的继承当中,如果要在子类中重写某个父类同名方法,该方法会覆盖父类的同名方法;但是,有的时候,我们在重写父类方法时,同时也要调用父类同名方法功能.这时,

我们可以通过使用super()方法来实现.比如:

 1 class Father:
 2     def __init__(self):
 3         print("Father.__init__")
 4 
 5 
 6 class Son(Father):
 7     def __init__(self):
 8         Father.__init__(self)       ##这种方法不推荐使用
 9         super(Son, self).__init__() ##主流用法
10         super().__init__()          ##python3 支持这个写法
11         print("Son.__init__")
12 
13 
14 s = Son()
15 
16 结果:
17 Father.__init__
18 Father.__init__
19 Father.__init__
20 Son.__init__

在上面,Father是父类,Son是子类,我们在Son中重定义了__init__()函数,但同时也想执行父类[Father]类的__init__方法,我们使用了super(),

super()有三种方法.主流方法是第二种...

深入了解super()

从上面的例子的示范,可能觉得super()的使用很简单,无非就是在重写父类的同时,调用父类的方法..其实,在上面的例子中,super()获得的类刚好是父类,

在其他的一些情况下就不一定了,super其实和父类没有任何实质性的联系.

一个复杂的例子,涉及到python 类的多重继承,我使用的是python3.

 1 class Base:
 2     def __init__(self):
 3         print("enter Base")
 4         print("leave Base")
 5 
 6 
 7 class A(Base):
 8     def __init__(self):
 9         print("enter A")
10         super().__init__()
11         print("leave A")
12 
13 
14 class B(Base):
15     def __init__(self):
16         print("enter B")
17         super().__init__()
18         print("leave B")
19 
20 
21 class C(A, B):
22     def __init__(self):
23         print("enter C")
24         super().__init__()
25         print("enter C")
26 
27 
28 c = C()

其中,Base是父类,A,B继承自Base,C继承A,B,继承关系图

    Base
    /  \
   /    \
  A      B
   \    /
    \  /
     C

代码执行结果:

1 enter C
2 enter A
3 enter B
4 enter Base
5 leave Base
6 leave B
7 leave A
8 enter C
View Code

看了结果,是不是和你想的有点不一样?你想的是不是,enter A的下一句enter Base?

这里的结果和我们所认为的有所差别.原因在于,super和父类是没有实质性的联系.下面让我们看看,super在程序中道理是如何运行的!

MRO列表

python的类继承,在我们每定义一个类,都会计算出一个方法解析顺序(Method Reselution Order,MRO)列表.我们可以使用下面的方式获得一个类的MRO列表.

print(C.mro())
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>]

一个类的 MRO 列表就是合并所有父类的 MRO 列表,并遵循以下三条原则:

  • 子类永远在父类前面
  • 如果有多个父类,会根据它们在列表中的顺序被检查
  • 如果对下一个类存在两个合法的选择,选择第一个父类

 

super原理

接上面代码后面

 1 def super(cls, inst):
 2     """
 3     1.获取inst的MRO列表
 4     2.查找cls在当前MRO列表中的index,并返回它的下一个类,即mro[index + 1]
 5     总结:当你使用 super(cls, inst) 时,Python 会在 inst 的 MRO 列表上搜索 cls 的下一个类。
 6     :param cls: 代表类
 7     :param inst: 代表实例
 8     :return:
 9     """
10     mro = inst.__class__.mro()
11     return mro[mro.index(cls) + 1]
12 ret = super(C,c)
13 print(ret)
14 结果:<class '__main__.A'>

好了,让我们回到之前的例子:

super(C,self).__init()

这里的self是当前C的实例,self.class.mro()结果:

1 [__main__.C, __main__.A, __main__.B, __main__.Base, object]

可以看出,C的下一个类是A,于是,跳到了A的__init__.这是会打印enter A,执行下一句

super(A,self).__init__()

注意,这里的 self 也是当前 C 的实例,MRO 列表跟上面是一样的,搜索 A 在 MRO 中的下一个类,发现是 B,于是,跳到了 B 的 __init__,这时会打印出 enter B,而不是 enter Base。

=.=

 

posted on 2017-03-01 10:16  定海偶然  阅读(153)  评论(0编辑  收藏  举报