我是MRO的新手,并且在确定这些输出的逻辑时遇到了问题。
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()
输出:
D
C
B
A
我的问题是super(C)
调用B.save()
的方式。
根据MRO:super(C, self)
不是关于“C
的基类”,而是关于C
的MRO列表中的下一个类。但是B
的MRO列表中没有C
。
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()
输出:
D
C
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()
输出:
D
C
A
如果B
不是从A
继承,而是直接从object
继承,那么MRO如何受到影响?
有人可以解释这背后的原因吗?
答案 0 :(得分:2)
为了解决这些问题,首先需要了解 MRO 和 super()的工作原理。
MRO Python Document - MRO
在Python中,MRO基于C3线性化。 (wiki和python文档中有很多例子)
super()(查看Python文档 - super())
根据Python文档,它说..
返回一个代理对象,该方法将方法调用委托给父或类型的兄弟类。这对于访问已在类中重写的继承方法很有用。搜索顺序与getattr()使用的搜索顺序相同,只是跳过了类型本身。
因此, super()将基于 MRO (classobject.__mro__
)进行搜索,并且它将由父类或兄弟类类型满足。< / p>
回到你的案件,
案例1
D.__mro__ = (D, C, B, A, object)
因此,输出将为D C B A
案例2
D的MRO与案例1中的D相同。((D, C, B, A, object)
)
但是, super()将在 C 停止或满意,因为C类中的save()
没有实现超级函数调用。
案例3
D的MRO等于(D, C, A, B, object)
。因此,当 super()在A类中达到save()函数时,它会认为满意。这就是为什么B中的保存功能从未被调用过的原因。
此外,如果您将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()。
此外,根据我的理解, super()不是强制子类对象在父类中调用所有覆盖函数的函数。如果要强制类调用其父类中的所有覆盖函数。您可以尝试执行以下操作:
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()时,输出将为:
GrandChild-method
Child-method
Parent-method
Base-method
注意:
GrandChild.__bases__
仅包含类Child和类Base
PS。
通过说上面的满意,我的意思是没有更多的super()调用。