在多重继承中调用超类方法

问题描述:

我有以下代码:

class A:
    pass

class B(A):
    def foo(self, a):
        if a:
            return 'B'
        return super(B, self).foo(a)

class C:
    def foo(self, a):
        return 'C'

class D(B, C):
    def foo(self, a):
        return super().foo(a)

d = D()
print(d.foo(0))

当我基于MRO调用d.foo(0)时,它首先调用B类的foo方法,在其中,如果条件错误,它将返回super(B, self).foo(0),但类A没有foo方法而且我期望这个错误:

When I call d.foo(0) based on MRO it first calls the foo method of B class and inside that, if the condition is wrong and it will return super(B, self).foo(0) but class A has no foo method and I expect this error:

AttributeError: 'super' object has no attribute 'foo'

,但它从类C返回'C'.为什么?

but it returns 'C' from class C. Why?

super()在MRO中搜索具有该属性的下一类A不实现它并不重要,因为仍在考虑C.

super() searches the MRO for the next class that has the attribute; that A doesn't implement it doesn't matter as C is still considered.

对于D,MRO为DBAC:

For D, the MRO is D, B, A, C:

>>> D.__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class 'object'>)

因此D中的super().foo将找到B.foo,并且从B.foo中跳过A并找到了C.foo;您可以从交互式解释器中对此进行测试:

so super().foo in D will find B.foo, and from B.foo, A is skipped and C.foo is found; you can test this yourself from the interactive interpreter:

>>> super(D, d).foo
<bound method B.foo of <__main__.D object at 0x1079edb38>>
>>> super(B, d).foo
<bound method C.foo of <__main__.D object at 0x1079edb38>>

这是属性搜索算法的Python实现的样子:

This is what a Python implementation of the attribute search algorithm would look like:

def find_attribute(type_, obj, name):
    starttype = type(obj)
    mro = iter(starttype.__mro__)

    # skip past the start type in the MRO
    for tp in mro:
        if tp == type_:
            break

    # Search for the attribute on the remainder of the MRO
    for tp in mro:
        attrs = vars(tp)
        if name in attrs:
            res = attrs[name]
            # if it is a descriptor object, bind it
            descr = getattr(type(res), '__get__', None)
            if descr is not None:
                res = descr(
                    res,
                    None if obj is starttype else obj,
                    starttype)
            return res

其中,type_super()的第一个参数(方法在其上定义的类),obj是实例(此处为type(d)),而name是您要查找的属性

where type_ is the first argument to super() (the class the method is defined on), obj is the instance (so type(d) here), and name is the attribute you are looking for.