【问题标题】:python multiple inheritance, calling base class functionpython多重继承,调用基类函数
【发布时间】:2016-12-28 06:14:43
【问题描述】:

我只是在 python 中尝试使用多重继承。我想出了这个

class ParentOne:
    def foo(self):
        print("ParentOne foo is called")

class ParentTwo:
    def foo(self):
        print("ParentTwo foo is called")

class Child(ParentOne, ParentTwo):

    # how is this working
    def call_parent_two_foo(self):
        super(ParentOne, self).foo()

    # This does not work
    def call_parent_foo(self):
        super(ParentTwo, self).foo()

    def call_super_foo(self):
        super(Child, self).foo()

    def foo(self):
        print("Child foo is called")


if __name__ == "__main__":
    child = Child()
    child.foo()
    child.call_super_foo()
    child.call_parent_two_foo()

    # child.call_parent_foo() #This gives the below error
    # super(ParentTwo, self).foo()
    # AttributeError: 'super' object has no attribute 'foo'

它给出以下输出

Child foo is called
ParentOne foo is called
ParentTwo foo is called

我对在这种情况下如何评估 super(ParentOne, self).foo() 的调用感到困惑。据我了解ParentOne 类对ParentTwo 类的方法和属性一无所知。在多重继承的情况下 super 是如何工作的

【问题讨论】:

    标签: python python-2.7 python-3.x inheritance


    【解决方案1】:

    Python 在构建类时会构建方法解析顺序 (MRO)。 MRO始终是线性的。如果 python 无法创建线性 MRO,则会引发 ValueError。在这种情况下,您的 MRO 可能如下所示:

    Child -> ParentOne -> ParentTwo -> object
    

    现在,当 python 看到 super(cls, self) 时,它基本上会查看 self 并找出 MRO。然后它使用cls 来确定我们当前在 MRO 中的位置,最后它返回一个委托给 MRO 中的 next 类的对象。因此,在这种情况下,super(Child, self) 调用将返回一个委托给ParentOne 的对象。 super(ParentOne, self) 类将返回一个委托给 ParentTwo 的对象。最后,super(ParentTwo, self) 调用将委托给object。换句话说,您可以将super 视为以下代码的更高级版本:

    def kinda_super(cls, self):
        mro = inspect.getmro(type(self))
        idx = mro.index(cls)
        return Delegate(mro[idx + 1])  # for a suitably defined `Delegate`
    

    请注意,由于super(ParentTwo, self) 将“代表”返回给object,我们可以看到为什么您在尝试super(ParentTwo, self).foo() 时会得到AttributeError -- 具体原因是因为object 没有@ 987654339@方法。

    【讨论】:

    • 是他们查看/获得 MRO 的一种方式
    • @AnuragSharma -- inspect.getmro 应该给你。 IIRC,您也可以通过魔术__mro__ 属性访问它。
    【解决方案2】:
    class X1:
        def run(self):
            print("x1")
    
    class X2:
        def run(self):
            print("x2")
    
    class X3:
        def run(self):
            print("x3")
    
    class X2:
        def run(self):
            print("x2")
    
    class Y(X1, X2, X3):
        def run(self):
            print("y")
    

    给定一个实例:

    y = Y()
    

    调用基类函数:

    super(Y,y).run()
    super(X1,y).run()
    super(X2,y).run()
    y.run()
    

    输出

    x1
    x2
    x3
    y
    

    相似性,

    super(Y, y).run()
    for cls in y.__class__.__bases__:
        if(cls != X3):
            super(cls,y).run()
    y.run()
    

    输出

    x1
    x2
    x3
    y
    

    【讨论】:

      【解决方案3】:

      您可以将Child(ParentOne, ParentTwo) 理解为链中的两个独立继承:Child(ParentOne(ParentTwo))。实际上,ParentOne 并没有继承 ParentTwo,它们是两个独立的类,但是 super 方法的工作方式就像有一个继承链(仅在多重继承的情况下)。我喜欢这个例子来更好地理解发生了什么(对于 Python 3.x):

      class P:
          def m(self):
              print("P")
      
      
      class A(P):
          def m(self):
              super().m() # -> B, if we inherit like C(A, B)
              print("A")
      
      
      class B(P):
          def m(self):
              super().m() # -> P, if we inherit like C(A, B)
              print("B")
      
      
      class C(A, B):
          def m(self):
              super().m() # -> A
              print("C")
              A.m(self)
              B.m(self)
      
      
      c = C()
      c.m()
      

      它还考虑两个父母继承一个基类的情况。上面的脚本打印:

      P
      B
      A
      C
      P
      B
      A
      P
      B
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-10
        • 1970-01-01
        • 1970-01-01
        • 2013-03-30
        • 2011-04-13
        • 2011-06-24
        相关资源
        最近更新 更多