MRO (Method Resolution order),主要用来解决继承中歧义的消除
1.在python2.2之前,菱形继承的顺序是:left-to-right,depth-first
class A:
^ ^ def save(self): ...
/ \
/ \
/ \
/ \
class B class C:
^ ^ def save(self): ...
\ /
\ /
\ /
\ /
class D
如上图:B和C都继承A,D继承B和C(所以D也继承了A)。
假设C重写了A中的save()
方法,B和D没有重写save()
。当我们在D的instance中调用save()
方法时,直接通过通过B再到A,最终调用的是A中的save()
方法,并没有调用C中的save()
方法。
就是因为这个原因,python2.2之前很少有多继承。
class B:
def m(self):
print "B here"
class C(B):
def m(self):
print "C here"
B.m(self)
上述代码:我们说C的方法"extends"B的方法,在单继承中这种写法没问题,但是在多继承中(菱形继承)就会出现问题:
class A(object): ..
class B(A): ...
class C(A): ...
class D(B, C): ...
假设A定义了方法m,B和C重写了A的方法m。D继承了BC,如果D使用m方法,则一般python仅仅获取第一个,这里使用B中的m方法。缺点就是忽视了C的m方法。比如,当我们想通过D来保存这个继承关系时,我们理论上是想保存ABCD四者,但是由于这种继承规则,只保存了ABD,而忽视了C。
C++
注意到这个问题,于是就是让D分别继承BC,重写BC的m方法,但这就出现另一个问题,A的m方法被调用了2次。
为了,解决这问题,就是在各自类中,定义_m
方法来存储自己的定义,m
方法来做继承:
class A(object):
def m(self): "save A's data"
class B(A):
def _m(self): "save B's data"
def m(self): self._m(); A.m(self)
class C(A):
def _m(self): "save C's data"
def m(self): self._m(); A.m(self)
class D(B, C):
def _m(self): "save D's data"
def m(self): self._m(); B._m(self); C._m(self); A.m(self)
但这种方法,仍然有很多问题:
1、产生了太多的方法
2、让被继承的的方法丢在子类中,比如我们不想让BC继承A,则需要手动修改BCD的代码。
最终"call-next-method"模式解决了这个问题:
class A(object):
def m(self): "save A's data"
class B(A):
def m(self): "save B's data"; super(B, self).m()
class C(A):
def m(self): "save C's data"; super(C, self).m()
class D(B, C):
def m(self): "save D's data"; super(D, self).m()
注意super
的第一个参数是class
自身,第二个参数是实例self
,注意self
没有在m方法中出现。
我们使用__mro__
来描述这样的继承关系
A.__mro__ == (A, object)
B.__mro__ == (B, A, object)
C.__mro__ == (C, A, object)
D.__mro__ == (D, B, C, A, object)
super(C,self).m
只在C中执行。虽然self
是C的instance,但是self.__class__
可能不是C,可能是C的子类,比如D。
super(C,self).m
会在self.__class__.__mro__
中查询C的继承关系。例如:
self
是一个C的instance,super(C,self).m
将找到A的m方法的实现。
D的m方法,super(D,self).m()
将找到B.m(self)
,因为B是D的第一个实现m的父类,在D.__mro__
。在B的m方法super(B,self).m()
被调用。
由于self
是D的instance,MRO是(D,B,C,A,object)B之后的继承关系是C。所以会找到C的m方法,调用super(C,self).m()
,仍然使用的是相同的MRO。类似的方法,然后继续寻找A。
class Super(object):
def __init__(self, type, obj=None):
self.__type__ = type
self.__obj__ = obj
def __get__(self, obj, type=None):
if self.__obj__ is None and obj is not None:
return Super(self.__type__, obj)
else:
return self
def __getattr__(self, attr):
if isinstance(self.__obj__, self.__type__):
starttype = self.__obj__.__class__
else:
starttype = self.__obj__
mro = iter(starttype.__mro__)
for cls in mro:
if cls is self.__type__:
break
# Note: mro is an iterator, so the second loop
# picks up where the first one left off!
for cls in mro:
if attr in cls.__dict__:
x = cls.__dict__[attr]
if hasattr(x, "__get__"):
x = x.__get__(self.__obj__)
return x
raise AttributeError, attr
class A(object):
def m(self):
return "A"
class B(A):
def m(self):
return "B" + Super(B, self).m()
class C(A):
def m(self):
return "C" + Super(C, self).m()
class D(C, B):
def m(self):
return "D" + Super(D, self).m()
print D().m() # "DCBA"
参考:
https://www.python.org/download/releases/2.2/descrintro/