超级方法如何在python中实际运行?
在给定的代码中:
class A(object):
def test(self):
return 'A'
class B(A):
def test(self):
return 'B->'+super(B, self).test()
class C(A):
def test(self):
return 'C'
class D(B,C):
pass
print B().test() # B->A
print D().test() # B->C ????
# MRO of classes are as
print 'mro of A', A.__mro__ # [A,object]
print 'mro of B', B.__mro__ # [B,A,object]
print 'mro of C', C.__mro__ # [C,A,object]
print 'mro of D', D.__mro__ # [D,B,C,A,object]
在D上调用test
时,它会输出B->C
而不是B->A
(我期待的那样)。
B中的super如何引用C的实例?
答案 0 :(得分:2)
来自文档:
super(type [,object-or-type]): 返回将方法调用委托给父类或兄弟类
的代理对象
强调我的。
MRO(已打印出来)确定方法分辨率顺序,在本例中为(D,B,C,A,对象)。因此,super(B, self)
在D
内调用时会返回一个代理对象,该代理对象会根据MRO将方法委托给其兄弟C
。
实际上,这可以用于在不修改现有类的情况下扩展继承层次结构中的行为。请注意B
实际上知道要将test()
方法分派到哪个类 - 它只是使用间接super()
调用。您只需创建一个以所需顺序混合多个基类的新类,即可在MRO中插入另一个类。
例如,假设您的原始层次结构仅包含类A
,B
和D
。假设,稍后您需要使用日志记录来检测所有B
方法调用。您可以简单地创建一个新的类B
来执行日志记录并使C
继承D
,而不是修改C
,从而将其插入到B之后的MRO中。
答案 1 :(得分:1)
通常情况下,super()接受两个参数:类和该类的实例。 (1)实例对象(self)确定将使用哪个MRO来解析任何属性。 (2)提供的类确定该MRO的子集,因为super()仅使用MRO中提供的类之后的那些条目。
因此,在上面的情况下,当从D对象的实例调用超级B内部时,self指向D对象(即实例对象),而D(即实例对象)的mro是[D,B,C,A]因此根据至(2)仅使用M之后出现的MRO条目。即[C,A]
因此,推荐的用法是提供使用super()作为第一个参数,将标准self作为第二个参数的类。生成的对象将保留self的实例命名空间字典,但它仅检索在稍后在MRO中找到的类上定义的属性,而不是提供的类。
因此,如果我们将B重新定义为
class B(A):
def test(self):
return 'B->'+super(C, self).test()
然后调用D()。test()将输出==> ' B->一种' 说明: 从(1)上面的自我MRO == [D,B,C,A,对象] 从上述(2)开始,只会使用在提供课程后发生的MRO条目(即C) 因此super将调用A的测试方法。