在多重继承的情况下,super方法如何在python中工作?

时间:2014-04-05 10:09:42

标签: python oop inheritance multiple-inheritance method-resolution-order

超级方法如何在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的实例?

2 个答案:

答案 0 :(得分:2)

来自文档:

  

super(type [,object-or-type]):   返回将方法调用委托给父类或兄弟

的代理对象

强调我的。

MRO(已打印出来)确定方法分辨率顺序,在本例中为(D,B,C,A,对象)。因此,super(B, self)D内调用时会返回一个代理对象,该代理对象会根据MRO将方法委托给其兄弟C

实际上,这可以用于在不修改现有类的情况下扩展继承层次结构中的行为。请注意B实际上知道要将test()方法分派到哪个类 - 它只是使用间接super()调用。您只需创建一个以所需顺序混合多个基类的新类,即可在MRO中插入另一个类。

例如,假设您的原始层次结构仅包含类ABD。假设,稍后您需要使用日志记录来检测所有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的测试方法。