钻石继承和 MRO
Diamond inheritance and the MRO
我是 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)
不是关于 "base class of C
",而是关于 C
的 MRO 列表中的下一个 class。但是 C
.
的 MRO 列表中没有 B
案例二:
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 会受到怎样的影响?
有人可以解释这背后的原因吗?
为了解决这些问题,您首先需要了解 MRO 和 super() 是如何工作的。
MRO Python Document - MRO
在Python中,MRO是基于C3线性化的。 (wiki和python文档中有很多例子)
super()(查看Python文档-super())
根据 Python 文档,它说..
Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used by getattr() except that the type itself is skipped.
因此,super()会根据MRO (classobject.__mro__
) 进行搜索,并且会被任何一方满足class 或同级 class 类型。
回到你的案例,
案例一
D.__mro__ = (D, C, B, A, object)
因此,输出将是 D C B A
案例二
D的MRO与情况1中的D相同。((D, C, B, A, object)
)
但是,super()会在C处停止,或者满足,因为classC中的save()
没有实现了超级函数调用。
案例三
D的MRO等于(D, C, A, B, object)
。因此,当 super() 到达 class A 中的 save() 函数时,它会认为满足。这就是为什么 B 中的保存函数从未被调用过的原因。
另外,如果将D的继承顺序从C、B改为B、C。(class D(C, B)
改为class D(B, C)
)。然后,当您调用 D().save()
时,输出将是 D B 因为 D.__mro__ = (D, B, C, A, object)
和 super() 将在 class B 处得到满足。
此外,根据我的理解,super() 不是强制子 class 对象调用 all 的函数覆盖父 classes 中的函数。如果你想强制你的 class 调用其父 classes 中的所有覆盖函数。您可以尝试执行以下操作:
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__
仅包含 class 子项和 class 基础
PS.
上面说 满意 ,我的意思是不再有 super() 调用。
我是 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)
不是关于 "base class of C
",而是关于 C
的 MRO 列表中的下一个 class。但是 C
.
B
案例二:
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 会受到怎样的影响?
有人可以解释这背后的原因吗?
为了解决这些问题,您首先需要了解 MRO 和 super() 是如何工作的。
MRO Python Document - MRO
在Python中,MRO是基于C3线性化的。 (wiki和python文档中有很多例子)
super()(查看Python文档-super())
根据 Python 文档,它说..
Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used by getattr() except that the type itself is skipped.
因此,super()会根据MRO (classobject.__mro__
) 进行搜索,并且会被任何一方满足class 或同级 class 类型。
回到你的案例,
案例一
D.__mro__ = (D, C, B, A, object)
因此,输出将是 D C B A
案例二
D的MRO与情况1中的D相同。((D, C, B, A, object)
)
但是,super()会在C处停止,或者满足,因为classC中的save()
没有实现了超级函数调用。
案例三
D的MRO等于(D, C, A, B, object)
。因此,当 super() 到达 class A 中的 save() 函数时,它会认为满足。这就是为什么 B 中的保存函数从未被调用过的原因。
另外,如果将D的继承顺序从C、B改为B、C。(class D(C, B)
改为class D(B, C)
)。然后,当您调用 D().save()
时,输出将是 D B 因为 D.__mro__ = (D, B, C, A, object)
和 super() 将在 class B 处得到满足。
此外,根据我的理解,super() 不是强制子 class 对象调用 all 的函数覆盖父 classes 中的函数。如果你想强制你的 class 调用其父 classes 中的所有覆盖函数。您可以尝试执行以下操作:
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__
仅包含 class 子项和 class 基础
PS.
上面说 满意 ,我的意思是不再有 super() 调用。