pannyvan

导航

Python 之 super & MRO (没有遇到过适用场景)

WOW!!!

这里wow的是真尼玛绕且没看完,

好困呐,贴上网址,等自己英文好一点再看(https://rhettinger.wordpress.com/2011/05/26/super-considered-super/),,,,

自己的理解:

先上例子:

例1:

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"

输出:

 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

按我们对super的理解,从图中可以看出,在调用类C的初始化函数时,应该是调用类A的初始化函数,但事实上却调用了类D的初始化函数。好一个诡异的问题!并且类A和类D的初始化函数被重复调用了2次

这是为什么呢?

super不是简单地调用所谓基类的方法,而是调用MRO中的下一个类的方法,也就是类似于next的方法。

mro中记录了一个类的所有基类的类类型序列。查看mro的记录,发觉包含7个元素,7个类名分别为:F E B C D A object

从而说明了为什么在C.__init__中使用super(C, self).__init__()会调用类D的初始化函数了。

不要一说到 super 就想到父类!super 指的是 MRO 中的下一个类!

MRO & super

Method resolution order是python用来解析方法调用顺序的。MRO对于多重继承中方法调用异常重要。python中有一个内建函数和MRO密切相关——super。具体实现方式,有兴趣可以以后看看。

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

super做了什么?

def super(cls, inst):
    mro = inst.__class__.mro()
    return mro[mro.index(cls) + 1]

两个参数 cls 和 inst 分别做了两件事:
1. inst 负责生成 MRO 的 list
2. 通过 cls 定位当前 MRO 中的 index, 并返回 mro[index + 1]

super的作用是什么呢?

按名字继承的话,如果子类的父类发生变化时,必须要全部替换名字,比较麻烦;

  

 

如果没有复杂的继承结构,super 作用不大。

例2:(没太看懂这货

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"

输出:

 enter F
 enter E
 enter B
 enter C
 enter D
 enter A
 leave A
 leave D
 leave C
 leave B
 leave E
 leave F

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

 

那么,总结:

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

2. super类的初始化函数并没有做什么特殊的操作,只是简单记录了类类型和具体实例;

3. super(B, self).func的调用并不是用于调用当前类的父类的func函数;

4. Python的多继承类是通过mro的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数只调用一次(如果每个类都使用super);

 

    如果类被设计成使用了super,那么所有子类也必须要调用super,否则直接调用会出现重复调用的问题

 

5. 混用super类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一个父类函数被调用多次。(保持一致性。要不全部用类名调用父类,要不就全部用 super,不要一半一半。)

 

参考:

http://www.cnblogs.com/lovemo1314/archive/2011/05/03/2035005.html(super)

http://blog.csdn.net/rommi/article/details/51058360(MRO)

http://blog.csdn.net/seizef/article/details/5310107(super & MRO) 

  

posted on 2016-12-05 19:23  pannyvan  阅读(221)  评论(0编辑  收藏  举报