在多重继承中调用 super class 方法

Calling super class method in multiple inheritance

我有以下代码:

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 class 的 foo 方法,在其中,如果条件错误,它将 return super(B, self).foo(0) 但 class A 没有 foo 方法,我预计会出现此错误:

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

但它 returns 'C' 来自 class C。为什么?

super() 在 MRO 中搜索 下一个 class 具有该属性; A 没有实现并不重要,因为 C 仍在考虑中。

对于 D,MRO 为 DBAC

>>> 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;你可以从交互式解释器中自己测试它:

>>> 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 实现如下所示:

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() 的第一个参数(class 定义了方法),obj 是实例(所以 type(d)此处),name 是您要查找的属性。