Python的多重继承和super

多重继承:

Python的多重继承和super_第1张图片

 

super:

不要一说到 super 就想到父类!super 指的是 MRO 表中的下一个类!super 其实干的是这件事:

def super(cls, inst):
    mro = inst.__class__.mro() # Always the most derived class
    return mro[mro.index(cls) + 1]

两个参数 cls 和 inst 分别做了两件事:

1. inst 负责生成 MRO 的 list

2. 通过 cls 定位当前 MRO 中的 index,并返回 mro[index + 1]

 

举例:

class Root(object):

    def __init__(self):

        print 'this is Root'

 

class B(Root):

    def __init__(self):

        print 'enter B'

        super(B, self).__init__()

        print 'leave B'

 

class C(Root):

    def __init__(self):

        print 'enter C'

        super(C, self).__init__()

        print 'leave C'

 

class D(B, C):

    pass

 

d = D()

print d.__class__.__mro__

 

输出:

enter B

enter C

this is Root

leave C

leave B

()

 

解释:

在 B 的 __init__() 函数中:

super(B, self).__init__()

 

首先,我们获取 self.__class__.__mro__,这里的 self 是 D 的 instance:

()

 

然后,通过 B 定位 MRO 中的 index,并找到下一个,显然是 C,于是,调用 C 的 __init__ 打印 enter C。

 

1)在 MRO 中,基类永远出现在派生类后面,如果有多个基类,基类的相对顺序保持不变。

2)super 是针对新式类的,如果用旧式类,就应该用类名去调用方法。

 

最后看两个列子:

例子1:

[root@zj py]# cat super1.py 

class A(object):

  def __init__(self):

   print "enter A"

   print "leave A"

class B(object):

  def __init__(self):

   print "enter B"

   print "leave B"

class C(A):

  def __init__(self):

   print "enter C"

   super(C, self).__init__()

   print "leave C"

class D(A):

  def __init__(self):

   print "enter D"

   super(D, self).__init__()

   print "leave D"

class E(B, C):

  def __init__(self):

   print "enter E"

   B.__init__(self)

   C.__init__(self)

   print "leave E"

class F(E, D):

  def __init__(self):

   print "enter F"

   E.__init__(self)

   D.__init__(self)

   print "leave F"

f = F()

[root@zj py]# python super1.py 

enter F

enter E

enter B

leave B

enter C

# 这里进入 D 的原因是 A 和 B 都是新式类,整个类继承图中的类就都是新式类,见下图1

# 因此符合新式类的广度优先搜索算法,会先进入 D 而不是 A,见 下图1 的绿色箭头

enter D

enter A

leave A

leave D

leave C

leave E

enter D

enter A

leave A

leave D

leave F

[root@zj py]# 

 

例子2:

[root@zj py]# cat super2.py 

class A(object):

  def __init__(self):

   print "enter A"

   super(A, self).__init__()  # new

   print "leave A"

class B(object):

  def __init__(self):

   print "enter B"

   super(B, self).__init__()  # new

   print "leave B"

class C(A):

  def __init__(self):

   print "enter C"

   super(C, self).__init__()

   print "leave C"

class D(A):

  def __init__(self):

   print "enter D"

   super(D, self).__init__()

   print "leave D"

class E(B, C):

  def __init__(self):

   print "enter E"

   super(E, self).__init__()  # change

   print "leave E"

class F(E, D):

  def __init__(self):

   print "enter F"

   super(F, self).__init__()  # change

   print "leave F"

f = F()

[root@zj py]# python super2.py 

enter F

enter E

enter B

enter C

# 这里进入 D 的原因是 A 和 B 都是新式类,整个类继承图中的类就都是新式类,见下图1

# 因此符合新式类的广度优先搜索算法,会先进入 D 而不是 A,见 下图1 的绿色箭头

enter D

enter A

leave A

leave D

leave C

leave B

leave E

leave F

[root@zj py]# 

 

Python的多重继承和super_第2张图片

(图片1)

 

说明:

用 super 时的输出是不同的。明显地,F 的初始化不仅完成了所有的父类的调用,而且保证了每一个父类的初始化函数只调用一次。

 

总结一下:

1. super 并不是一个函数,是一个类名,形如 super(B, self) 事实上调用了 super 类的初始化函数,产生了一个 super 对象;

2. super 类的初始化函数并没有做什么特殊的操作,只是简单记录了类类型和具体实例;
3. super(B, self).func 的调用并不是用于调用当前类的父类的 func 函数;
4. Python 的多继承类是通过 mro 的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数只调用一次(如果每个类都使用 super);

5. 混用 super 类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一个父类函数被调用多次。

6. 用 super,遇到修改父类的名字时等情况,可以少修改代码,参考:http://www.jb51.net/article/66912.htm

 

参考:

https://www.zhihu.com/question/20040039

http://blog.csdn.net/imzoer/article/details/8737642#

https://rhettinger.wordpress.com/2011/05/26/super-considered-super/

http://stackoverflow.com/questions/15896265/python-super-inheritance-and-arguments-needed/15896594#15896594

http://www.jb51.net/article/66912.htm

 

你可能感兴趣的:(python)