object.\__mro__

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/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值