Python的多重继承和super

来源:互联网 发布:计算圆周率的算法 编辑:程序博客网 时间:2024/05/16 19:49
多重继承:


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
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Root'>, <type 'object'>)

解释:
在 B 的 __init__() 函数中:
super(B, self).__init__()

首先,我们获取 self.__class__.__mro__,这里的 self 是 D 的 instance:
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Root'>, <type 'object'>)

然后,通过 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
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
enter D
enter A
leave A
leave D
leave C
leave B
leave E
leave F
[root@zj py]# 

说明:
用 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

0 0
原创粉丝点击