首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >钻石继承与MRO

钻石继承与MRO
EN

Stack Overflow用户
提问于 2017-03-08 07:15:32
回答 1查看 1.7K关注 0票数 8

我是MRO的新手,很难理解这些输出的逻辑。

案例1:

代码语言:javascript
复制
class A(object):
  def save(self):
      print "A"

class B(A):
    def save(self):
        print "B"
        super(B, self).save()

class C(A):
  def save(self):
      print "C"
      super(C, self).save()


class D(C, B):
    def save(self):
        print "D"
        super(D,self).save()

D().save()

输出:

代码语言:javascript
复制
D
C
B
A

我的问题是super(C)是如何调用B.save()的。

根据MRO:super(C, self)不是关于“C的基类”,而是关于C列表中的下一个类。但C的MRO列表中没有C

案例2:

代码语言:javascript
复制
class A(object):
  def save(self):
      print "A"

class B(A):
    def save(self):
        print "B"
        super(B, self).save()

class C(A):
  def save(self):
      print "C"
      # removed super call here

class D(C, B):
    def save(self):
        print "D"
        super(D,self).save()

D().save()

输出:

代码语言:javascript
复制
D
C

案例3:

代码语言:javascript
复制
class A(object):
  def save(self):
      print "A"

class B(object):
    #inherits object now instead of A
    def save(self):
        print "B"
        super(B, self).save()

class C(A):
  def save(self):
      print "C"
      super(C, self).save()

class D(C, B):
    def save(self):
        print "D"
        super(D,self).save()

D().save()

输出:

代码语言:javascript
复制
D
C
A

问题

如果B不是从A继承,而是直接从object继承,那么MRO是如何影响的?

有人能解释一下背后的原因吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-06-14 03:49:53

为了解决这些问题,您首先需要了解MRO超级()是如何工作的。

MRO Python文档- MRO

在Python中,MRO是基于C3线性化的。( wiki和python文档中有许多示例)

超级()(查看Python超级())

根据Python文档,它说..。

返回代理对象,该对象将方法调用委托给类型为类型的父类兄弟类。这对于访问已在类中重写的继承方法非常有用。搜索顺序与getattr()使用的顺序相同,只是类型本身被跳过。

因此,超级()将基于MRO (classobject.__mro__)进行搜索,并且它将被类型的父类或兄弟类所满足。

回到你的案子,

案例1

D.__mro__ = (D, C, B, A, object)

因此,输出将是D C B A

案例2

在案例1中,D的MRO与D相同。((D, C, B, A, object))

但是,超级()将停止或满足于C,因为C类中的save()没有实现超级函数调用。

案例3

D的MRO等于(D, C, A, B, object)。因此,当超级()达到A类中的save()函数时,它会认为满足。这就是为什么从来没有调用B中的save函数的原因。

此外,如果将D的继承序列从C、B转换到B、C (class D(C, B)class D(B, C))。然后,当您调用D().save()时,输出将是D B,因为在B类将满足D.__mro__ = (D, B, C, A, object)和super()。

此外,据我理解,超级()不是强制子类对象调用父类中的all覆盖函数的函数。如果要强制类调用其父类中的所有重写函数,请执行以下操作。你可以试着做这样的事情:

代码语言:javascript
复制
class Base(object):
    def method(self):
        print('Base-method')

class Parent(object):
    def method(self):
        print('Parent-method')

class Child(Parent):
    def method(self):
        print('Child-method')
        super(Child, self).method()

class GrandChild(Child, Base):
    def method(self):
        print('GrandChild-method')
        for base in GrandChild.__bases__:
            base.method(self)
        #super(GrandChild, self).method()

然后,当调用‘`GrandChild().method()时,输出将是:

代码语言:javascript
复制
GrandChild-method
Child-method
Parent-method
Base-method

注意:

GrandChild.__bases__只包含类子类和类基

PS。

通过在上面说满意,我的意思是不再有超级()调用。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42665175

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档