Steven D'Aprano <steve+python@pearwood.info> added the comment: On Fri, Jun 07, 2019 at 09:57:11AM +0000, Jeroen Demeyer wrote:
I'm having problems with the first word of "a parent or sibling class of type".
The first word is "a". Did you mean something else or did you mean it literally? If the second case, we have to talk about *a* parent class rather than *the* parent class, since Python supports multiple inheritance and a class can have more than one parent class.
The most important part of super() is to *which* class that attribute lookups are delegated to and this is not explained.
Lookups are delegated to a parent or sibling class, exactly as the documentation says. Which class that is (whether a parent or sibling) can only be determined at runtime.
And the sentence "The __mro__ attribute of the type lists the method resolution search order used by both getattr() and super()" is even wrong or at least confusing: what matters is not the MRO of the type (the first argument to super()) but the MRO of ***the type of*** the object (the second argument to super()).
I believe that is still wrong. What matters is the __mro__ attribute of the first argument. It matters because that is how the MRO actually is searched. The MRO of the second argument is not relevant, except to the degree that it overlaps with the __mro__ attribute of the first. And it will always overlaps, because the second argument must be an instance or subclass of the first. But not necessarily *directly* of the first: object > Parent > A > B > C > D > E > F > instance = F() If the method is defined in class C, then the super call in C should be written: class C(B): def method(self, arg): super().method(arg) # like super(C, self).method(arg) and the lookup will start at C.__mro__[1], namely B, precisely as expected. If it started back at the type of the instance (self), namely class F, the C.method would recursively call itself over and over and over again. If you don't believe me, you can simulate super() working the way you suggest by doing this: # -----%<----- class A(object): def method(self): print("from class A") class B(A): def method(self): print("bad method") # This is bad, don't do it! super(type(self), self).method() class C(B): pass C().method() # -----%<----- For multiple inheritance: class C(B, X, Y, Z): ... we can't generally tell in advance which will be looked at next, since that depends on the precise details of the inheritance diagram. But whatever the class is, at this point, it is still the __mro__ of C that is used, not the MRO of the instance. The bottom line: what matters is <first argument>.__mro__, exactly as documented. ---------- _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue37176> _______________________________________