super 类不只是恢复超类。它实例化一个对象,该对象在给定的方法解析顺序的上下文中恢复方法。每个类都有一个mro,您可以通过__mro__ 属性访问它。
D.__mro__ # (D, B, C, A, object)
所以当给定一个类和一个实例时,super 首先从那个实例中恢复 mro。当您尝试从 super 对象中恢复属性时,它会从提供的具有此类属性的类之后的第一个类中返回该属性。
如果你要在 Python 中实现 super 的行为,它看起来像这样。
class super:
def __init__(self, cls, instance):
if not isinstance(cls, type):
raise TypeError('super() argument 1 must be type')
if isinstance(instance, cls):
self.mro = type(instance).__mro__
elif isinstance(instance, type) and issubclass(instance, cls):
self.mro = instance.__mro__
else:
raise TypeError('super(type, obj): obj must be an instance or subtype of type')
self.cls = cls
self.instance = instance
def __getattr__(self, attr):
cls_index = self.mro.index(self.cls)
for supercls in self.mro[cls_index + 1:]:
if hasattr(supercls, attr): break
# The actual implementation binds instances to methods before returning
return getattr(supercls, attr)
回到你的例子,当你调用super(B, self).go时,它会恢复self的__mro__,它的类型是D。然后,它从 mro 中 B 之后的第一个类中选择 go,该类具有此类属性。
所以在这种情况下,由于self.__mro__ 是(D, B, C, A, object),所以B 之后具有go 属性的第一个类是C 而不是A。
如果您想了解 Python 如何确定 mro 的详细信息,那么我建议您使用abarnert's answer。