Python超级旁路MRO

时间:2014-02-25 19:20:37

标签: python inheritance super method-resolution-order

我有一个继承的类并覆盖了一个也从基类继承的方法。但问题是中间方法创建了一个异常,我想通过调用第一个声明的方法来绕过它。有没有办法指定忽略第二次调用的 mro

一个例子可能是:

class Base(object):
     def __init__(self):
         res = "Want this"
         print res

class BaseA(Base):
      def __init__(self):
          res = super(BaseA, self).__init__()
          res = "Not this"
          print res

class BaseB(BaseA):
      def __init__(self):
          res = super(BaseB, self).__init()
          #At this poing res is "Not this"
          #The desire is that it would be "Want this"
          print res

非常感谢

PD: 像BaseB(Base,BaseA)这样的东西可以工作吗?

3 个答案:

答案 0 :(得分:5)

通常你会修改该方法。

然而,super()的第一个参数是从开始搜索下一个方法的地方。通常,这是当前的类,但您也可以传入基类:

class BaseB(BaseA):
    def __init__(self):
        res = super(BaseA, self).__init__()

此处,super()获取type(self)的MRO,在该MRO中找到BaseA,并查找实施__init__的下一个类。

绕过有问题的__init__方法的另一种方法是直接在Base上调用未绑定的方法:

class BaseB(BaseA):
    def __init__(self):
        res = Base.__init__(self)

完全绕过任何MRO搜索。

答案 1 :(得分:2)

解决此问题的正确方法是创建一个新的类层次结构,该层次结构使用改进的实现覆盖违规方法。如果你坚持使用hackery,这可能是你想要的:

class BaseB(BaseA):
      def __init__(self):
          res = super(BaseA, self).__init()
          #At this poing res is "Not this"
          #The desire is that it would be "Want this"
          print res

请注意,我要求针对BaseA的超级实现,这意味着永远不会使用BaseA实现。


然而,当涉及钻石继承时,这个可以做错误的事情。考虑:

class Base(object):
    def __init__(self):
        print 'initing Base'

class BaseA(Base):
    def __init__(self):
        print 'initing BaseA'
        res = super(BaseA, self).__init__()

class BaseB(BaseA):
    def __init__(self):
        print 'initing BaseB'
        res = super(BaseA, self).__init__()

class BaseC(BaseA):
    def __init__(self):
        print 'initing BaseC'
        res = super(BaseC, self).__init__()

class BaseD(BaseB, BaseC):
    def __init__(self):
        print 'initing BaseD'
        res = super(BaseD, self).__init__()

print BaseD()

输出结果为:

initing BaseD
initing BaseB
initing Base
<__main__.BaseD object at 0x7f1e693a0110>

BaseC被删除了,即使这不是我们想要的。这是因为BaseC在方法解析顺序中位于BaseBBaseA之间,所以当我们从BaseB跳到BaseA时,我们无意中忽略了BaseC }。

>>> print [cls.__name__ for cls in BaseD.mro()]
['BaseD', 'BaseB', 'BaseC', 'BaseA', 'Base', 'object']

答案 2 :(得分:0)

如何回合

Base.__init__(self)